http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58969
Bug ID: 58969 Summary: bogus error: the value of 'kName' is not usable in a constant expression Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: ppluzhnikov at google dot com Google ref: b/11479502 /// --- cut --- template <const char name[]> class BaseObject { virtual const char* GetName() const { return name; } }; const char kName[] = "name"; class Object : public BaseObject<kName> { }; int main() { return 0; } /// --- cut --- Using g++ (GCC) 4.9.0 20131028 (experimental) g++ -c t.cc t.cc:9:34: error: 'kName' cannot appear in a constant-expression class Object : public BaseObject<kName> { ^ t.cc:9:39: error: template argument 1 is invalid class Object : public BaseObject<kName> { ^ g++ -c t.cc -std=c++11 t.cc:9:34: error: the value of 'kName' is not usable in a constant expression class Object : public BaseObject<kName> { ^ t.cc:8:12: note: 'kName' was not declared 'constexpr' const char kName[] = "name"; ^ Compiles with Clang. Analysis by Richard Smith: This is a GCC bug. It appears to be some sort of confusion in the way GCC handles internal linkage non-type template parameters of pointer type. You can also get GCC to accept the code by marking kName as 'extern'. Obligatory standards references (relative to N3797): [temp.param](14.1)/8: "A non-type template-parameter of type "array of T" [...] is adjusted to be of type "pointer to T". [temp.arg.nontype](14.3.2)/1: "A template-argument for a non-type, non-template template-parameter shall be [...] a constant expression that designates the address of a complete object with static storage duration and external or internal linkage [...] expressed [...] as & id-expression, where the id-expression is the name of an object [...], except that the & may be omitted if the name refers to a[n] [...] array" Note that "kName" is a constant expression, because it is a glvalue core constant expression whose value refers to an object with static storage duration (see [expr.const](5.19)/4). [temp.arg.nontype](14.3.2)/5: "The following conversions are performed on each expression used as a non-type template-argument. [...] For a non-type template-parameter of type pointer to object, [...] the array-to-pointer conversion [is] applied." So BaseObject has a template parameter of type 'const char*', and that parameter can bind to the template argument kName (after array-to-pointer decay). There's no requirement that kName be declared 'constexpr'; its value is not used here, only its address is used.