扔进 constexpr 函数:我们需要包装条件吗?

Kon*_*rov 5 c++ constexpr c++17

基本思想是这样的:我有一些constexpr函数,我想用它throw来发出错误信号和延迟编译以避免正常流程中出现此错误:

template <size_t N>
auto constexpr find_elt(const std::array<int, N>& a, int k) {
  for (size_t i = 0; i < N; ++i)
    if (k == a[i])
      return i;
  throw "not found";
}
Run Code Online (Sandbox Code Playgroud)

进而:

constexpr int result = find_elt(arr, 4);
Run Code Online (Sandbox Code Playgroud)

通常,如果数组中存在 4,我将在编译时获取其索引。

如果没有,我就会陷入困境throw编译时的查找是错误的,并且编译器将产生一个漂亮的错误。

但我注意到奇怪的行为:

在最新的 clang 下,一切正常

在最新的gcc下,一切都失败了

这个想法合法吗?这段代码对于我想要实现的目标是否正确?哪个编译器在这里告诉我真相?

如果不是,正确的方法是什么?

任何到 C++ 标准的链接都值得赞赏。我通读了 constexpr 相关的章节,但我有疑问。

小智 2

所以:

\n
    \n
  1. 由于 constexpr 函数的编译是一个“惰性”过程,因此仅在编译器在表达式替换期间仍然进入的范围内执行对 constexpr 函数是否符合要求的检查。
  2. \n
  3. 函数分别是一个作用域 - constexpr 的所有规则都必须在函数的第一级作用域的整个函数体中遵守。
  4. \n
  5. 并且由于表达式“throw”不是常量表达式(正如 gcc-10 编译器已经告诉我们的那样),因此未观察到正确性。
  6. \n
\n

clang 编译器在这个意义上并不像 gcc 那样严格。因此,这场战斗,在我看来,gcc获胜。他更加致力于标准。\n另一方面,如果这是一个“懒惰”的过程,那么为什么不应该偷懒到底呢。好吧,你找到了最终的返回值 - 那么为什么还要进一步检查正确性呢?\n从这个意义上说,clang 得到了一点。

\n

最后 - C++17 标准怎么说?

\n

10.1.5 constexpr 说明符 [dcl.constexpr]

\n
    \n
  1. “...如果不存在参数值 \xe2\x80\x8b\xe2\x80\x8be,使得函数或构造函数的调用可以是核心常量表达式 (8.20) 的计算子表达式,...,程序是格式错误,无需诊断。
  2. \n
\n

接下来我们看看“核心常量表达式”是什么:

\n

8.20 常量表达式[expr.const]

\n
    \n
  1. 表达式是一个计算,遵循抽象机(4.6)的规则,将计算以下表达式之一:
  2. \n
\n

2.22 - 一个 throw 表达式 (8.17)

\n

并注意“不需要诊断”并且编译器不需要提供失败原因的详细解释。

\n