Странный синтаксис для передачи параметра const char для определения длины в качестве параметра шаблона. Что происходит?

Я нашел эту жемчужину в нашей кодовой базе.

constexpr bool ConstexprStrBeginsWithImpl(const char* str, const char* subStr)
{
    return !subStr[0] ? true : (str[0] == subStr[0] && ConstexprStrBeginsWithImpl(str + 1, subStr + 1));
}
template<int N, int M>
constexpr bool ConstexprStrBeginsWith(const char(&str)[N], const char(&subStr)[M])
{
    static_assert(M <= N, "The substring to test is longer than the total string");
    return ConstexprStrBeginsWithImpl(str, subStr);
}

Теперь я понимаю, что он делает (сравнивая две константные строки как constexpr), но что это за странный синтаксис вызова const char(&str)[N]? для вывода int-параметра шаблона с длиной константы char? Как это работает? Как это законный синтаксис? : -O

Я думал, вам нужно объявить параметр постоянного массива символов следующим образом: const char str[N]?

Если я использую эту - для меня более логичную - версию, то мои компиляторы (VCL и GCC) жалуются, что они не могут вывести int-параметр N при использовании constexpr в качестве параметра для другого шаблона с bool. Например, в этом сценарии:

template<bool B> struct Yada { int i = 23; };
template<> struct Yada<true> { int i = 42; };
int main()
{
    Yada<ConstexprStrBeginsWith("foobar", "foo")> y;
    std::cout << y.i;
}

Это компилируется только в том случае, если я объявляю str и subStr через const char(&str)[N], а не просто const char str[N].

Итак ... я счастлив, что он компилируется и выглядит, конечно, умно, но ... допустим ли этот синтаксис? Что здесь заявлено? : -О. #просто любопытно

Привет, Ими.


person Imi    schedule 03.03.2021    source источник
comment
const char (&str)[N] - это ссылка на массив из N символов. Скобки необходимы, потому что const char &str[N] будет массивом N ссылок на символы. Зачем нужна ссылка, кто-нибудь еще ответит ...   -  person Thomas    schedule 03.03.2021
comment
И C-массив нельзя передать по значению (они распадаются на указатели). std::add_reference_t<const char[N]> можно было бы использовать, если бы это можно было вычесть. Так что вы можете переписать его на template <typename T, std::size_t N> using c_array = T[N];, а затем на template<std::size_t N, std::size_t M> constexpr bool ConstexprStrBeginsWith(const c_array<char, N>&, const c_array<char, M>&);   -  person Jarod42    schedule 03.03.2021
comment
это ответ (половина) на ваш вопрос? stackoverflow.com/questions/5724171/   -  person 463035818_is_not_a_number    schedule 03.03.2021


Ответы (1)


Благодаря @Thomas, @ Jarod42 и @most_prime_is_463035818 я смог собрать пазл воедино:

  1. Знак & перед строкой означает объявление ссылки на массив символов вместо массива символов по значению. Скобки необходимы из-за обязательных правил.
  2. Причина того, что шаблон не может определить размер массива char, если он передается по значению, заключается в том, что эти старые c-массивы распадаются на указатели, тогда как ссылки на C-массивы никогда не распадаются. В Jarod42 есть хороший пример того, как вместо этого использовать шаблоны - если (по какой-то причине) вам не нравится использовать ссылки на c-массивы.
person Imi    schedule 03.03.2021