Let's suppose we have a template function with non-type parameter of const char *
like this:
template <const char * MESSAGE> void print() {
std::cout << MESSAGE << '\n';
}
Using this template wouldn't be a problem as log as the MESSAGE
can be deduced at compile-time, so the following uses are legal:
namespace {
char namespace_message[] = "Anonymous Namespace Message";
constexpr char namespace_constexpr_message[] = "Anonymous Namespace Constexpr Message";
}
char message[] = "Message";
constexpr char constexpr_message[] = "Constexpr Message";
int main()
{
print<namespace_message>();
print<namespace_constexpr_message>();
print<message>();
print<constexpr_message>();
return 0;
}
But the ones below are not (see here):
namespace {
const char namespace_const_message[] = "Anonymous Namespace Const Message";
}
const char const_message[] = "Const Message";
int main()
{
print<namespace_const_message>();
print<const_message>();
print<"Literal">();
return 0;
}
The errors generated by the code above are the following:
the value of '{anonymous}::namespace_const_message' is not usable in a constant expression
I don't get why namespace_const_message
is not usable in a constant expression while namespace_message
is; if I must bet for one of them to be unable to be used in a constant expression I'll bet for the no constant one, but is the one which already works as constant expression!
note: '{anonymous}::namespace_const_message' was not declared 'constexpr'
namespace_message
was neither declared as constexpr
and is used into a constant expression and its value is deduced at compile time. Why constexpr
is needed if the expression is const
and not required if no-const?
Same goes for the values outside the anonymous namespace, I was trying to force the compile-time-constness placing the values into a internal linkage space but is obvious that I've failed.
Finally, the last error:
'"Literal"' is not a valid template argument for type 'const char*' because string literals can never be used in this context
So, surprisingly (at least it was a surprise for me) a string literal cannot be used as template argument, but as long as the string (well, a pointer to a null-terminated array of characters) is a compile-time value it can be used as non-type template parameters so: they're available at compile-time as long as "they are a lvalue" (but they're already lvalues!).
I'm trying to guess why a string literal can never be used in this context, and my best guess is that two string literals with the same content aren't the same literal (because the pointer which points to the content could be different) while two integral literals are the same (they're a value, not a pointer to a value).
So, what's the question here?
- Why the
namespace_const_message
andconst_message
aren't available at compile-time and thus forbidden in theprint
template function? - Is my guess about the string literals correct?
Thanks.