【问题标题】:How to get a compile time error in constant evaluated expression?如何在常量评估表达式中获得编译时错误?
【发布时间】:2020-04-23 22:00:12
【问题描述】:

我有一个 Assert 函数用于评估断言:

  • 如果运行时前置条件失败,该函数将输出错误信息并终止程序。

  • 如果前置条件在常量表达式中失败,则会导致编译时错误。

我希望这个函数在常量评估表达式中的断言失败时也会生成编译时错误:

const int a = (Assert(false),0); //generate a runtime error 
                                 //=> I would like it generates a compile time error

我考虑过使用std::is_constant_evaluatedcompiler-explorer

#include <type_traits>

using namespace std;

void runtime_error();

constexpr void compile_time_error(){} //should generates a compile time error

constexpr void Assert(bool value){
   if (value) return;
   if (is_constant_evaluated())
     compile_time_error();
   else
     runtime_error();
   }

void func(){
    const int a = (Assert(false),0);
    }

我只使用 GCC,我寻找了一个会导致编译时错误的内置函数,这将是一个 constexpr,但没有找到。

有什么技巧可以让表达式中的编译时错误可以被常量评估?

【问题讨论】:

  • static_assert 在编译时进行评估。因此,它检查的表达式必须是constexpr,而不仅仅是const。这就是问题所在:你的函数 compile_time_error 函数的编译总是会失败。
  • 只需使用runtime_error()。如果在编译时求值会报错。

标签: c++ gcc assertion c++20 constant-expression


【解决方案1】:

您可以调用未定义的函数来导致编译时错误。或者,由于您无论如何都在使用 gcc,您可以从常量部分内部调用属性错误函数,以在本单元编译期间导致编译时错误。要使其工作,您必须在启用优化的情况下进行编译。

我看到 std::is_constant_expression 在 gcc 9.2 中不起作用,但我设法让它与 __builtin_constant_p 一起使用。

#include <type_traits>

constexpr void Assert(bool value) {
   if (__builtin_constant_p(value)) {
        if (!value) {
            extern __attribute__(( __error__ ( "error" ) ))
            void compile_time_error(void);
            compile_time_error();
        }
    } else {
        if (!value) {
            void runtime_error();
            runtime_error();
        }
   }
}

void func(int b) {
    const int a = (Assert(false), 0);
    Assert(b == 0);
}

我曾经用 C 语言编写了一个名为 curb 的库,它可以做这样的事情。

【讨论】:

  • GCC 仍然尊重常量初始化合约,并改为定期初始化 godbolt.org/z/afrvEM
  • 谢谢!实际上它只适用于__builtin_constant_p,不适用于is_constant_evaluate()
  • 这是否保证了标准的错误,还是只是常见的行为?
  • 标准中没有关于__builtin_constant_p 的内容。这是一个私人 gcc 调用。因此,它既不能保证有效,也不能保证常见行为。但它应该适用于当前版本的 gcc。
  • 请注意,这个答案并不依赖于 Assert(false) 是(部分)常量表达式;如果编译器知道参数(可能是因为优化),它就会触发。
猜你喜欢
  • 1970-01-01
  • 2012-12-26
  • 1970-01-01
  • 2014-06-16
  • 2016-11-11
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多