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

时间:2016-09-11 20:12:45

标签: 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;
}

另一方面,这个有效。

typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
  s<&fn> x;
}

1 个答案:

答案 0 :(得分:6)

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

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

  

非类型非模板的 template-argument    template-parameter 应为以下之一:

     

[...]

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

(我只包括与指针和指针成员直接相关的项目符号。)

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

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

  • DR1570澄清了有关完整对象的内容;
  • DR1398修改的
  • DR1666添加了最后一颗子弹。

对于C ++ 17,由于采用了文件N4268N4198中的基本原理),因此放宽了限制。相应的第(2)段现在说:

  

非类型模板参数 template-argument 应为   转换常数表达式(5.20)的类型   模板参数。对于非类型模板参数的引用或   指针类型,常量表达式的值不得参考   (或者对于指针类型,不应该是地址):

     
      
  • 子对象(1.8),
  •   
  • 临时对象(12.2),
  •   
  • 字符串文字(2.13.5),
  •   
  • __func__表达式(5.2.8)或
  • 的结果   
  • 预定义的public String get(int i) { if(i<0 || i>=lenght) return null; return iter(head, i) } public String iter(Node t,int i){ if(t == null) return null; if(i == 0) return t.elemnt; return iter(t.next, i - 1) } 变量(8.4.1)。
  •   
     

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

N4198包含每个子弹的良好解释。