常量变量作为非类型模板参数(VARIABLE不能出现在常量表达式中)

8
为什么这个有效呢?
char __nontype[] = "foo";
typedef TemplateClass<T, __nontype> MyClass;

但这个(使用常量变量)不行吗?
const char __nontype[] = "foo";
typedef TemplateClass<T, __nontype> MyClass;

编译器错误:

错误:'__nontype'不能出现在常量表达式中

错误:模板参数2无效


2
这可能取决于TemplateClass<>的定义。你能发布一下吗? - hatboyzero
我认为这里的根本误解在于您假定 const 修饰符会自动使某些东西成为 constexpr。字符数组不是编译时常量;它们直到链接时才被知道。 - tenfour
@tenfour 你错过了一个重要点,使用char数组是可以的。这是因为一些链接时常量表达式是有效的模板参数。 - user743382
2个回答

6
区别在于const会影响链接。如果添加extern, 它就有效了。话虽如此,据我所知:
14.3.2 模板非类型参数[temp.arg.nontype] 非类型非模板模板参数的模板参数应为以下之一:
  • 整数常量表达式(包括可以用作整数常量表达式的字面类类型的常量表达式,如5.19中所述);或者
  • 非类型模板参数的名称; 或者
  • 指定具有静态存储期和外部或内部链接的对象的地址或具有外部或内部链接的函数的常量表达式(5.19),包括函数模板和函数模板id,但不包括非静态类成员,表示为& id-expression(忽略括号),但如果名称引用函数或数组,则可以省略&,如果相应的模板参数是引用,则必须省略&; 或者
  • 计算值为空指针值的常量表达式(4.10); 或者
  • 计算值为零成员指针值的常量表达式(4.11); 或者
  • 按照5.3.1所述表示的成员指针。
没有extern也可以正常工作。对象允许具有内部链接,但您的编译器尚不支持。这是C++11中的一个变化,之前的C++标准不允许这样做。

1
好的,这似乎是问题所在。很好的答案!据我所知,允许内部链接是新的(C++11?)。但为什么不允许呢? - ejoerns
1
@ejoerns 我不知道这是否是全部原因,但只允许具有外部链接的对象和函数可以更容易地确保所有不同模板实例化的名称都不同。 - user743382
1
@ejoerns,你说得对,这在C++11中是新的。顺便说一下,我刚刚查了一下。 - user743382

1
错误提示如下:结果不是常量表达式(在链接时已知,但在编译时未知)。
以下是一个示例,它可以正常工作:
typedef const char *nontype_t;
template <nontype_t> struct Y {};

char hello[] = "hello";
constexpr char* world = hello;

int main()
{
    Y<hello> a;
}

我不明白。指向字符的指针与指向常量字符的指针有什么区别,它们怎么能被称为对象的指针呢? - user743382
1
那你为什么引用规范中处理哪些类型是可接受的部分呢? - user743382
它可能是一个具有静态存储期的对象,取决于模板参数的类型,那么它将是有效的。问题可能是参数的类型是具有非const char类型的数组。 - Richard Corden
@sehe,这仍然没有解释const和non-const之间的区别,因为您仍然定义了一个可修改的char数组,即使您将其(间接地)转换为指向const-char的指针。据我所知(请参见我的答案),不应该有任何区别。 - user743382

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接