【问题标题】:can a static constexpr variable be used as a template argument可以将静态 constexpr 变量用作模板参数吗
【发布时间】:2016-09-11 20:12:45
【问题描述】:

我有以下代码可以在较旧的 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;
}

【问题讨论】:

  • 那里的静态关键字不会使变量成为私有变量,它使它成为具有持久存储的运行时值,在第一次调用函数时被初始化...
  • @KerrekSB 但我没有获取变量的地址,我使用的是它的值,它在编译时初始化为具有明显可接受链接的东西的地址,因为值本身工作。
  • 错误信息不是很有帮助。也就是说,函数的地址必须严格表示为&amp;fnfn。这只是 C++14 及以下标准中指定的限制,C++17 取消了该限制。这就是代码在 C++1z 模式下在两个编译器上编译的原因。抄送@KerrekSB
  • @bogdan 是明确要求此限制还是在 c++17 之前未指定。我问的原因是 gcc-4.8.5 和 gcc-5.3.0 接受代码为有效。或者这是在 gcc-6 中修复的 gcc 中的错误?
  • @bogdan 我认为您应该写一个答案,以便我接受。我希望能提供一些关于标准在 c++11、14、17 中的内容以及它如何变化的额外信息。无论如何谢谢。

标签: c++ templates constexpr


【解决方案1】:

第一个 sn-p 在 C++17 中是正确的,但在 C++14 和 11 中不正确。

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

非类型、非模板的 模板参数 模板参数应为以下之一:

[...]

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

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

基本上,示例中函数的地址必须严格表示为&amp;fnfn

C++11 包含基本相同的措辞,但在 11 和 14 之间的缺陷报告中引入了一些澄清:

  • DR1570 澄清了关于完整对象的一点;
  • DR1398DR1666 修改添加了最后一个项目符号。

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

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

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

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

N4198 对每个项目符号都有很好的解释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    相关资源
    最近更新 更多