【问题标题】:Constexpr and templates: compiler bug?Consexpr 和模板:编译器错误?
【发布时间】:2019-02-05 05:41:57
【问题描述】:

以下按预期工作:

#include <array>
constexpr std::array<int, 3> values = {1, 2, 3};
template <int i> struct A { static constexpr int val = values[i]; };
int main() { A<1> a; }

但是,如果我们使用values.size() 作为模板参数,我会从 MSVC 编译器中得到一个编译器错误:

int main() { A<values.size()> a; }

错误是表达式未计算为常量。 GCC 编译没有错误。

  • 这是 MSVC 编译器的错误吗?
  • 是否有标准/巧妙的解决方法来规避此错误?

【问题讨论】:

  • 哪个版本的 MSVC?
  • 版本“x64 msvc v19.16”,见godbolt.org/z/fwpIAH
  • 解决方法很简单,不是吗? int main() { A&lt;3&gt; a; }
  • 顺便说一句,我可能会更改标题,这里没有单个编译器错误,那么为什么要“另一个”? ;)
  • 我改了标题。由于 GCC 会编译而 MSVC 不会,“编译器错误?”看起来很合适。

标签: c++ templates constexpr


【解决方案1】:

MSVC 是对的。在任何 constexpr 上下文中都不能有未定义的行为。否则这不是一个常量表达式。

行:

int main() { A<values.size()> a; }

基本上是:

constexpr auto i = values[values.size()];

这是超出范围的。事实上,MSVC 正确诊断错误:

example.cpp
<source>(3): error C2131: expression did not evaluate to a constant
C:/msvc/v19_16/include\array(187): note: failure was caused by out of range index 3; allowed range is 0 <= index < 3
<source>(4): note: see reference to class template instantiation 'A<3>' being compiled 
<source>(2): note: see reference to class template instantiation 'std::array<int,3>' being compiled
Compiler returned: 2

另一方面,GCC 和 MSVC 都接受此代码:

int main() { A<values.size() - 1> a; }

【讨论】:

    【解决方案2】:

    这实际上是 GCC 的错误/缺陷,而不是 MSVC。

    A<values.size()> a;
    

    导致您访问超出范围的values,因为有效索引为[0, size())。 MSVC 给你一个错误,它不能这样做,因为它是未定义的行为,并且在常量表达式中是不允许的。

    请注意,clang 也可以正确诊断并发出错误:https://godbolt.org/z/vmi86S

    【讨论】:

      猜你喜欢
      • 2020-10-13
      • 1970-01-01
      • 1970-01-01
      • 2015-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-24
      • 1970-01-01
      相关资源
      最近更新 更多