我有以下代码在旧版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;
}
答案 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
的常量表达式。
(我只包括与指针和指针成员直接相关的项目符号。)
基本上,样本中函数的地址必须严格表示为fn
或typeid
。
C ++ 11包含基本相同的措辞,减去11和14之间缺陷报告引入的一些说明:
对于C ++ 17,由于采用了文件N4268(N4198中的基本原理),因此放宽了限制。相应的第(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包含每个子弹的良好解释。