在默认模板参数中调用 constexpr
Calling constexpr in default template argument
在 C++11 中,我使用 constexpr 函数作为模板参数的默认值 - 它看起来像这样:
template <int value>
struct bar
{
static constexpr int get()
{
return value;
}
};
template <typename A, int value = A::get()>
struct foo
{
};
int main()
{
typedef foo<bar<0>> type;
return 0;
}
G++ 4.5 和 4.7 编译了这个,但 Clang++ 3.1 没有。来自 clang 的错误消息是:
clang_test.cpp:10:35: error: non-type template argument is not a constant expression
template <typename A, int value = A::get()>
^~~~~~~~
clang_test.cpp:17:19: note: while checking a default template argument used here
typedef foo<bar<3>> type;
~~~~~~~~~^~
clang_test.cpp:10:35: note: undefined function 'get' cannot be used in a constant expression
template <typename A, int value = A::get()>
^
clang_test.cpp:4:23: note: declared here
static constexpr int get()
^
1 error generated.
哪一个是正确的?
LLVM IRC频道的Richard Smith(zygoloid)与我就此问题进行了简短的交谈,这是您的答案
<litb> hello folks
<litb> zygoloid, what should happen in this case?
<litb> http://stackoverflow.com/questions/10721130/calling-constexpr-in-default-template-argument
<litb> it seems to be clang's behavior is surprising
<litb> zygoloid, i cannot apply the "point of instantiation" rule to constexpr
function templates. if i call such a function template, the called definition's
POI often is *after* the specialization reference, which means at the point of
the call, the constexpr function template specialization is "undefined".
<zygoloid> it's a horrible mess. Clang does not do what the standard intends, but
as you note, the actual spec is gloriously unclear
<d0k> :(
<zygoloid> we should instantiate bar<3>::get(), because it is odr-used, but we
don't, because we incorrectly believe it's used in an unevaluated context
<zygoloid> conversely, the point of instantiation is too late :/
<zygoloid> PR11851
因此,似乎有时,Clang 实例化调用的函数模板或类模板的成员函数,但它们的实例化为时已晚,调用无法看到,而在其他情况下,它甚至不实例化它们,因为它认为它永远不会需要它们(未计算的上下文)。
我认为GCC Clang是正确的
引自N3290:
14.3.2 模板非类型参数 [temp.arg.nontype]
非
- 类型、非模板模板参数的模板参数应为以下参数之一:
- 对于整型或枚举类型的非类型模板参数,模板参数类型的转换>常量表达式 (5.19);或
- 。
编辑: 5.19 3
文字常量表达式是文本类型,但不是指针类型。积分常量表达式为整型或无作用域枚举的文本常量表达式类型。[ 注意:此类表达式可用作数组边界(8.3.4,5.3.4),作为位字段长度 (9.6),作为枚举器初始值设定项(如果基础类型不固定)(7.2),作为空指针常量 (4.10),和对齐方式(7.6.2)。—尾注 ] 转换后的常量表达式的类型 T 是一个文字常量表达式,隐式转换为类型 T,其中隐式转换(如果有)在文字常量表达式和隐式转换序列仅包含用户定义的转换、左值到右值转换(4.1)、积分促销 (4.5) 和积分转化 (4.7) 其他而不是缩小转换范围 (8.5.4)。
[注意:此类表达式可用作大小写表达式 (6.4.2),如果基础类型是固定的,则用作枚举器初始值设定项 (7.2),以及用作整数或枚举非类型模板参数 (14.3)。
- 在 constexpr funnction 中调用basic_string函数
- 调用模板参数 constexpr 方法?
- 在模板定义中调用非静态constexpr成员函数
- 为什么 std::get<T> 其中 T 是调用 constexpr 函数失败的结果?
- 在enable_if_t中调用 constexpr 函数
- 是否有一种非间接、非黑客的方式来保证 constexpr 函数仅在编译时可调用?
- 对 constexpr 与内联函数的调用编译为不同的程序集,并禁用优化
- constexpr vs重复函数调用性能
- 触发编译时间错误时,constexpr函数的超载被调用
- 为什么 gcc5.4 不编译调用非 constexpr 函数的 constexpr 函数,而 icpc 可以编译?
- 模板推导指南可以调用constexpr函数吗
- 如何在constexpr函数中有效地调用_BitScanReverse或__builtin_clz
- 当编译时参数未知时,不调用"constexpr"构造函数
- 为什么我可以在constexpr函数中调用一个非constexpr的函数
- 在常量表达式上下文中的定义之前嵌套的“constexpr”函数调用
- 为什么调用此constexpr静态成员函数时不将其视为constexpr
- 只要调用的函数是用constexpr指定的,就将委托方法声明为constexpr
- 在默认模板参数中调用 constexpr
- C++VS2015 constexpr编译错误,constexpr构造函数调用constexpr成员函数
- 在常量初始化器中调用constexpr构造函数的限制