#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 给出以下错误:
error C2975: 'S': invalid template argument for 'arr', expected compile-time constant expression error C2131: expression did not evaluate to a constant
这个程序是否符合 C++14 标准,或者 gcc 在这里太宽松了?
最佳答案
据我所知,该程序格式正确。
根据 [temp.param]/8,模板参数实际上具有类型 const int*
,而不是 const int[]
。
A non-type template-parameter of type “array of
T
” or “function returningT
” is adjusted to be of type “pointer toT
” or “pointer to function returningT
”, respectively.
根据[temp.arg.nontype]/1,我们可以使用具有静态存储持续时间和外部链接的完整数组对象的名称作为这样一个模板参数的实参:
A template-argument for a non-type, non-template template-parameter shall be one of:
...
— a constant expression (5.19) that designates the address of a complete 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, where the id-expression is the name of an object or function, 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 ...
arr
是一个常量表达式,尽管 MSVC 认为它不是。根据 [expr.const]/2,它是一个核心常量表达式,因为它不包含任何禁止的计算,并且它是一个常量表达式,因为它指向一个具有静态存储持续时间的对象 ([expr.const]/4)。
因为模板参数引用了一个静态存储持续时间的数组,所以数组的边界在模板实例化时是已知的。因此它可以验证对 arr[0]
的访问是合法的核心常量表达式,因为它具有明确定义的行为并且属于 [expr.const 中允许的左值到右值转换的类别]/2:
... a non-volatile glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression
关于c++ - 使用 constexpr 数组作为模板非类型参数 (C++14),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43528101/