The main problem in your code is not terminating the template recursion, but rather the fact that array + 1
is not a valid template non-type argument, as specified in [14.3.2] in the Standard. For C++11 and 14, such an argument has to have a specific form, &
id-expression, possibly omitting the &
. After C++14, the requirements have been relaxed and expressed in terms of the updated rules for constant expressions, but still, an argument cannot be the address of a subobject; this excludes any pointer arithmetic, since that's defined in terms of addresses of subobjects.
If you insist on using a solution based on class templates (not my first choice, see below), you can work around that by avoiding pointer arithmetic in the template argument; here's one way to do it, including the check to end the template recursion:
#include <iostream>
#include <cstddef>
template<const char* P, std::size_t I = 0, char = P[I]> struct len
{
static constexpr std::size_t value = len<P, I + 1>::value + 1;
};
template<const char* P, std::size_t I> struct len<P, I, 0>
{
static constexpr std::size_t value = 0;
};
constexpr char a[] = "this is a test";
int main()
{
constexpr auto s = len<a>::value;
std::cout << s << '\n';
}
For clarity, I used char
as the element type, since that's what you're looking for as far as I understand. The solution can obviously be extended to any T
that can be the type of a non-type template parameter. For a T
that can't be passed directly, that last template parameter can be a bool
that receives the result of calling a constexpr
predicate that determines the end condition.
However, a much simpler and clearer solution involves basically implementing strlen
in a constexpr
function; you can use such a call expression as a template argument, even in C++11, as long as it's a constant expression. For C++14, it's as simple as this:
#include <iostream>
#include <cstddef>
constexpr std::size_t const_len(const char* p)
{
std::size_t i = 0;
while(p[i] != 0) ++i;
return i;
}
extern constexpr char a[] = "this is a test";
int main()
{
constexpr auto s = const_len(a);
std::cout << s << '\n';
}
A recursive solution complying with the C++11 constexpr
rules is equally straightforward.