使用constexpr数组作为模板非类型参数(C ++ 14)

时间:2017-04-20 19:17:46

标签: c++ gcc visual-c++ c++14 constexpr

#include <iostream>

using namespace std;

template<const int arr[]>
struct S {
    static constexpr int value = arr[0];
};

constexpr int arr[] = { 5 };

int main() {
    cout << S<arr>::value << endl;
}

此程序编译正常并使用gcc 5.1及更高版本打印5,但MSVC 19.10.25019会出现以下错误:

  

错误C2975:'S':'arr'的模板参数无效,是预期的   编译时常量表达式错误C2131:表达式没有   评估为常数

这个程序是否符合C ++ 14标准,或者gcc在这里太宽松了?

1 个答案:

答案 0 :(得分:2)

据我所知,该计划格式正确。

根据[temp.param] / 8,模板参数实际上具有const int*类型,而不是const int[]

  

类型为“T数组”或“函数返回T”的非类型模板参数被调整为类型   “指向T的指针”或“指向函数返回T的指针”。

根据[temp.arg.nontype] / 1,我们可以使用具有静态存储持续时间的完整数组对象的名称和外部链接作为这种模板参数的参数:

  

非类型非模板模板参数 template-argument 应为以下之一:

     

...

     

- 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的完整对象的地址,或具有外部或内部链接的函数,包括函数   模板和函数 template-ids 但不包括非静态类成员,表示(忽略括号)为& id-expression ,其中 id-表达式是对象或函数的名称,除了   如果名称引用函数或数组,则可省略&,如果相应,则可省略arr    template-parameter 是一个参考...

arr[0]是一个不变的表达,尽管MSVC认为它不是。它是根据[expr.const] / 2的核心常量表达式,因为它不包含任何禁止的计算,并且它是一个常量表达式,因为它指向具有静态存储持续时间的对象([expr.const] / 4)。

因为模板参数引用具有静态存储持续时间的数组,所以在模板实例化时已知数组的边界。因此,它可以验证对<dd><?php print $age; ?></dd> 的访问是否是合法的核心常量表达式,因为它具有明确定义的行为并且属于[expr.const] / 2中允许的左值到右值转换的类别:

  

...整数或枚举类型的非易失性glvalue,它引用非易失性const对象   前面的初始化,用常量表达式初始化