【问题标题】:Type conversion at template non-type argument without constexpr没有 constexpr 的模板非类型参数的类型转换
【发布时间】:2016-03-01 15:35:05
【问题描述】:

考虑以下代码:

struct A {
    constexpr operator int() { return 42; }
};

template <int>
void foo() {}

void bar(A a) {
    foo<a>();
}

int main() {
    foo<A{}>();

    const int i = 42;
    foo<i>();  // (1)

    A a{};

    static_assert(i == a, "");
    bar(a);
    foo<a>();  // error here
}

带有 c++14 的 Clang 3.7 接受这一点,而带有 c++14 的 gcc 5.2.0 不接受,产生以下消息:

/tmp/gcc-explorer-compiler1151027-68-1f801jf/example.cpp: In function 'int main()':
26 : error: the value of 'a' is not usable in a constant expression
foo<a>();
^
23 : note: 'a' was not declared 'constexpr'
A a{};
^
Compilation failed

按照 gcc 的建议将 a 更改为 constexpr 可修复 gcc 编译错误,但没有 constexpr,哪个编译器是正确的?

对我来说,a 似乎应该“可用于常量表达式”,正如static_assert 所证明的那样。而且i可以用同样的方式(标记(1)),bar()编译,也让我觉得gcc错了。

UPD:报告了一个针对 gcc 的错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68588

【问题讨论】:

  • const 更改为constexpr 工作Demo
  • @Jarod42,是的,看看我的编辑。

标签: c++ templates gcc clang c++14


【解决方案1】:

[expr.const]/(4.1) 允许用户定义的转换,我在[expr.const]/2 中看不到一个适用的项目符号点,这会阻止您的表达式成为一个常量。事实上,要求太宽松了,将a 声明为

A a;

still giving a well-formed program,即使a 没有constexpr 默认构造函数等,因为转换运算符是constexpr 并且没有成员被评估。

正如您所见,GCC 是矛盾的,因为它允许 a 出现在 static_assert 条件中,但不允许模板参数。

【讨论】:

    【解决方案2】:

    我会说 Clang 是正确的。

    当前 C++ (n4296) 的草稿说:

    14.3.2 模板非类型参数 [temp.arg.nontype]

    非类型模板参数的模板参数应是转换后的常量表达式 (5.20) 模板参数的类型

    5.20 §4 说(强调我的):

    5.20 常量表达式 [expr.const]

    ...

    (4) T 类型的转换常量表达式是一个表达式,隐式转换为 T 类型,其中转换后的 表达式是一个常量表达式,隐式转换序列只包含

    (4.1) — 用户定义的转换,...​​

    foo&lt;a&gt;(); a 中的 IFAIK 使用 constexpr 用户定义的转换转换为 int,因此 转换后的常量表达式。

    话虽如此,我们离极端情况不远了,我的建议是:不要在生产代码中使用这样的构造:-)

    【讨论】:

      【解决方案3】:

      正如@Jarod42 建议的那样,a 应该是 constexpr。这是因为模板是在编译时推导出来的,因此非类型参数也必须在编译时可用。 constexpr 承诺它们将在编译时可用。

      【讨论】:

      • 我完全知道constexpr 解决了这个问题(另请参阅我的编辑)。
      • 如果是这样,那么这应该告诉你哪个实现是正确的。
      猜你喜欢
      • 1970-01-01
      • 2017-02-09
      • 1970-01-01
      • 2018-06-17
      • 2019-04-24
      • 2014-01-12
      • 1970-01-01
      • 1970-01-01
      • 2021-03-18
      相关资源
      最近更新 更多