如何使 consteval 函数失败?

nih*_*hit 4 c++ c++20 consteval

我有以下功能:

template <size_t TSize>
consteval size_t indexOf(SomeEnum someEnum,
                         const std::array<SomeEnum, TSize> &arr) {
  for (size_t i = 0; i < TSize; ++i) {
    if (arr[i] == someEnum) {
      return i;
    }
  }
  // How to fail here?
  return SOME_DEFAULT_WRONG_VALUE;
}
Run Code Online (Sandbox Code Playgroud)

该函数应该失败而不是返回默认值,但我不能抛出异常或调用assert. 我可以static_assert在每次调用函数时添加一个(使用宏它会不那么可怕),但我更喜欢在函数中工作的解决方案。在这种情况下有没有办法触发编译失败?

Bar*_*rry 12

在这种情况下有没有办法触发编译失败?

如果目标是触发编译失败,那么最简单的方法就是抛出异常。异常是什么无关紧要,因为它实际上不会被抛出,抛出异常的行为将触发编译错误,因为在常量评估时间不允许抛出:

template <size_t TSize>
consteval size_t indexOf(SomeEnum someEnum,
                         const std::array<SomeEnum, TSize> &arr) {
  for (size_t i = 0; i < TSize; ++i) {
    if (arr[i] == someEnum) {
      return i;
    }
  }

  throw "failed to find someEnum";
}
Run Code Online (Sandbox Code Playgroud)

如果你想更明确,你可以有一个constexpr没有定义的非函数:

void trigger_consteval_failure(char const*);

template <size_t TSize>
consteval size_t indexOf(SomeEnum someEnum,
                         const std::array<SomeEnum, TSize> &arr) {
  for (size_t i = 0; i < TSize; ++i) {
    if (arr[i] == someEnum) {
      return i;
    }
  }

  trigger_consteval_failure("failed to find someEnum");
}
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,如果您要查找数组中的值,调用此函数是一个有效的常量表达式。但是如果没有找到索引,那么我们最终会做一些现在允许在常量表达式中的事情,不管怎样,这都是一个硬编译错误,正如我们所希望的。

如果我们能在这种情况下产生更好的堆栈跟踪,那就太好了,但我认为实际上没有办法做到这一点。

  • @Jarod42 这是他们在 [10.3](https://godbolt.org/z/7qT5K3WEf) 中修复的错误 (3认同)
  • gcc 拒绝 ` throw` :( [演示](https://godbolt.org/z/cPPcTEs6v) (2认同)

Jar*_*d42 7

你可以简单地省略 return

template <size_t TSize>
consteval size_t indexOf(SomeEnum someEnum,
                         const std::array<SomeEnum, TSize> &arr) {
  for (size_t i = 0; i < TSize; ++i) {
    if (arr[i] == someEnum) {
      return i;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

演示(clang 警告该方法)。

编译器将拒绝到达该路径的代码。

演示

throw 异常似乎更干净:

template <size_t TSize>
consteval size_t indexOf(SomeEnum someEnum,
                         const std::array<SomeEnum, TSize> &arr) {
  for (size_t i = 0; i < TSize; ++i) {
    if (arr[i] == someEnum) {
      return i;
    }
  }
  throw 42; // or more meaningful exception
}
Run Code Online (Sandbox Code Playgroud)

演示