首页 > 解决方案 > 抛出 constexpr 函数:我们需要包装条件吗?

问题描述

基本思想是这样的:我有一些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";
}

接着:

constexpr int result = find_elt(arr, 4);

通常,如果数组中存在 4,我会在编译时取回它的索引。

如果不是,我会throw指出在编译时查找是错误的,并且编译器会产生一个漂亮的错误。

但我注意到奇怪的行为:

在最新的叮当声下,一切正常

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

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

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

感谢任何指向 C++ 标准的链接。我通读了与 constexpr 相关的章节,但我对此表示怀疑。

标签: c++c++17constexpr

解决方案


所以:

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

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

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

10.1.5 constexpr 说明符 [dcl.constexpr]

  1. “......如果不存在任何参数值,使得函数或构造函数的调用可以是核心常量表达式(8.20)的评估子表达式,......,程序是错误的,不需要诊断。

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

8.20 常量表达式 [expr.const]

  1. 表达式是对的求值,遵循抽象机 (4.6) 的规则,将求值以下表达式之一:

2.22 - 抛出表达式 (8.17)

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


推荐阅读