2017-04-20 97 views
3
#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; 
} 

该程序编译细并打印5用gcc 5.1和更高,但MSVC 19.10.25019给出如下错误:使用constexpr阵列作为模板非类型参数(C++ 14)

错误C2975:“S”:为“改编”无效模板参数,预计 编译时间常数表达式错误C2131:表达没有 计算为一个常数

这是程序合法根据C++ 14 Standard还是gcc在这里太宽大了?

+0

对于初始化记录,Clang也接受这个代码。 – jwimberley

+0

如果用'arr [1]'替换'arr []',MSVC会说什么? – jwimberley

+0

@jwimberley它不会改变任何东西。 –

回答

2

该程序是完整的,据我所见。

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

一种非型模板参数类型的“阵列的T”或“函数返回T”被调整为类型 “指针T”或“函数指针返回T”,分别。

根据[temp.arg.nontype]/1,我们可以使用具有静态存储持续时间和外部连接的一个完整的阵列对象的名称作为参数传递给这样的模板参数:

对于非A型,非模板模板参数一个模板参数应是一个:

...

- 常量蚂蚁表达式(5.19)指定具有静态存储持续时间和外部或内部链接的完整对象的地址,或者包含功能 模板和函数template-id,但不包括非静态类成员,表达(忽略括号内)作为&ID-表达,其中ID-表达是一个对象或函数的名称,不同的是 &可以省略如果名称是指功能或阵列和将被省略如果相应的 模板参数是一个参考...

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

因为模板参数是指具有静态存储持续时间的数组,所以在模板实例化时数组边界是已知的。因此它可以验证对arr[0]的访问是一个合法的核心常量表达式,因为它具有定义明确的行为,并且属于[expr中允许的左值到右值转换的类别。常数]/2:

...整型或枚举类型的非易失性glvalue引用到非易失性const对象与前述 一个初始化,以恒定表达

+0

从技术上讲,它违反了[temp.arg.nontype] /2.1:“对于指针类型的非类型模板参数,常量表达式的值不应该是......的地址子对象”。指针指向数组的第一个元素,它是一个子对象。但是,这是目前的措辞已知的问题;请参阅CWG 2043。 –

相关问题