1

I found this gem in our codebase.

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);
}

Now I get what it does (comparing two constant strings as a constexpr), but what is this strange calling syntax const char(&str)[N]? to deduce the template int-parameter with the length of a constant char? How does this work? How is that a legal syntax? :-O

I thought you had to declare a constant char array parameter like this: const char str[N]?

If I use that - to me more logical - version, then my compilers (VCL and GCC) complain that they can't deduce the int-parameter N when using the constexpr as a parameter to another template with a bool. For example in this scenario:

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;
}

This only compiles, if I declare str and subStr via const char(&str)[N] instead of just const char str[N].

So.... I am happy that it compiles and it looks certainly clever, but.. is this legal syntax? What is declared here? :-O. #justcurious

Greetings, Imi.

Imi
  • 1,579
  • 1
  • 12
  • 22
  • `const char (&str)[N]` is a reference to an array of `N` characters. The parentheses are needed because `const char &str[N]` would be an array of `N` references to characters. Why the reference is needed, somebody else will have to answer... – Thomas Mar 03 '21 at 08:31
  • 1
    And C-array cannot be passed by value (they decay to pointers). `std::add_reference_t` might be used, if only it was deducible. So you might rewrite it to `template using c_array = T[N];` and then `template constexpr bool ConstexprStrBeginsWith(const c_array&, const c_array&);` – Jarod42 Mar 03 '21 at 08:39
  • does this answer (half of) your question? https://stackoverflow.com/questions/5724171/passing-an-array-by-reference – 463035818_is_not_an_ai Mar 03 '21 at 08:45

1 Answers1

0

Thanks to @Thomas, @Jarod42 and @largest_prime_is_463035818, I could piece the puzzle together:

  1. The & before the "str" is to declare a reference to an char-array instead of a char array by-value. The parenthesis are needed due to binding rules.
  2. The reason that the template can not deduce the size of the char array if passed by-value is, that these old c-arrays are decaying to pointers, whereas references to C-arrays are never decaying. Jarod42 has a nice example of how to use templates instead - if (for some reason) you don't like to use references to c-arrays.
Imi
  • 1,579
  • 1
  • 12
  • 22