可以将静态constexpr变量用作模板参数

Mar*_*tin 12 c++ templates constexpr

我有以下代码编译旧的gcc,但不是版本6(与-std = c ++ 1z一起使用).Clang也反对它,说对象val没有正确的联系.我不明白其中的区别.是不是指针类型的constexpr变量应该或多或少透明地工作?是否有一些我在语法中缺少的东西可以让它工作?或者这违反了标准的某些部分?

typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
  static constexpr t_voidfn val = &fn;
  s<val> x;
}
Run Code Online (Sandbox Code Playgroud)

另一方面,这个工作.

typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
  s<&fn> x;
}
Run Code Online (Sandbox Code Playgroud)

bog*_*dan 6

第一个片段在C++ 17中是正确的,但在C++ 14和11中则没有.

对于C++ 14,[temp.arg.nontype]/1表示:

模板参数的用于非类型,非模板 模板参数应是以下之一:

[...]

  • 一个常量表达式(5.19),用于指定具有静态存储持续时间和外部或内部链接的完整对象的地址,或具有外部或内部链接的函数,包括函数模板和函数模板ID,但不包括非静态类成员,表达(忽略括号)作为& id-expression,其中id-expression是对象或函数的名称,除非&如果名称引用函数或数组可以省略,如果相应的template-parameter是引用则应省略 ; 要么
  • 一个常量表达式,其值为空指针值(4.10); 要么
  • 一个常量表达式,其值为null成员指针值(4.11); 要么
  • 指向成员的指针,如5.3.1所述; 要么
  • 类型的常量表达式std::nullptr_t.

(我只包括与指针直接相关的子弹和指向成员的指针.)

基本上,样本中函数的地址必须严格表示为&fnfn.

C++ 11包含基本相同的措辞,减去11和14之间缺陷报告引入的一些说明:

  • DR1570澄清了有关完整物体的信息;
  • DR1666修改的DR1398添加了最后一颗子弹.

对于C++ 17,由于采用了N4268纸(N4198中的基本原理),因此放宽了这些限制.相应的第(2)段现在说:

模板参数的用于非类型模板参数应为的类型的一个转换后的常量表达式(5.20) 模板参数.对于引用或指针类型的非类型模板参数,常量表达式的值不应引用(或者对于指针类型,不应该是地址):

  • 子对象(1.8),
  • 一个临时物体(12.2),
  • 字符串文字(2.13.5),
  • typeid表达式(5.2.8)的结果,或
  • 预定义__func__变量(8.4.1).

[ 注意:如果template-argument表示一组重载函数(或指向此类的指针或成员指针),则从集合中选择匹配函数(13.4).- 结束说明 ]

N4198对每个子弹都有很好的解释.