问题
The rules of restrictions for template non-type arguments say:
A template-argument for a non-type, non-template template-parameter shall be one of:
— for a non-type template-parameter of integral or enumeration type, a converted constant expression (5.19) of the type of the template-parameter; or
— the name of a non-type template-parameter; or
— a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage or a function with external or internal linkage, including function templates and function template-ids but excluding non-static class members, expressed (ignoring parentheses) as & id-expression, except that the & may be omitted if the name refers to a function or array and shall be omitted if the corresponding template-parameter is a reference; or
— a constant expression that evaluates to a null pointer value (4.10); or
— a constant expression that evaluates to a null member pointer value (4.11); or
— a pointer to member expressed as described in 5.3.1.
2 [ Note: A string literal (2.14.5) does not satisfy the requirements of any of these categories and thus is not an acceptable template-argument.
[ Example:
template<class T, const char* p> class X {
/ ... /
};
X<int, "Studebaker"> x1; // error: string literal as template-argument
const char p[] = "Vivisectionist";
X<int,p> x2; // OK
—end example ] —end note ]
So why string literal cannot used as argument for non-type parameter?
const char arr[5] = "1234";
arr has same type const char[5] as
"1234";
arr has external linkage and that is why it was allowed to use arr as non-type template argument before c++11 standard.
But now pointers to objects with internal linkage(static storage) also allowed to use as non-type template arguments and string literal has internal linkage.
回答1:
The closest that string literals come to being allowed is, from your question:
a constant expression (5.19) that designates the address of an object with static storage duration and external or internal linkage
String literals have neither external linkage nor internal linkage, so they aren't allowed.
If you have multiple translation units, each containing a definition of const char arr[5];
with internal linkage, then those are all distinct objects, with distinct addresses, but within a single translation unit, arr == arr
, always. Implementations figured out how to make that work for template arguments.
If you have multiple translation units, each containing "1234"
, then those are not guaranteed to have distinct addresses. Yet even in a single translation unit, they are not guaranteed to have the same address.
If "1234" != "1234"
, then referring to a template S<"1234">
makes no sense: you'd be referring to a different template instantiation each time.
If "1234" == "1234"
, then it gets complicated for implementations to make sure that S<"1234">
is the same type in each translation unit.
回答2:
Really interesting that the following code is valid C++11, but string literals won't work. For C++14 you can even remove the static_cast.
#include <iostream>
static constexpr const char s1[] = "Hello World!";
static const char s2[] = __DATE__ " " __TIME__;
template< const char* STR > struct X {X() {std::cout << STR << std::endl;}};
X< s1 > x1;
X< static_cast<const char*>(s2) > x2;
int main() {}
Even if string literals are not accepted by today's C++ compilers, allowing this would be very handy in some cases.
Accepting addresses of temporary class instantiations as NT template argument would head into a similar direction:
#include <iostream>
struct S {int s;};
static constexpr const S s1{123};
static const S s2{999};
template< const S* _S > struct X {X() {std::cout << _S->s << std::endl;}};
X< &s1 > x1;
X< &s2 > x2;
//NOT OK: X< (&S{1}) > x3;
int main() {}
来源:https://stackoverflow.com/questions/28763443/template-non-type-argument-c11-restriction-for-string-literals