Как получить ошибку времени компиляции в постоянном вычисляемом выражении?

У меня есть Assert функция, которую я использую для оценки утверждения:

  • если предварительное условие не выполняется во время выполнения, эта функция выдаст сообщение об ошибке и завершит программу.

  • если предварительное условие не выполняется внутри константного выражения, это вызовет ошибку времени компиляции.

Я хотел бы, чтобы эта функция также генерировала ошибку времени компиляции, когда утверждение не выполняется в постоянном вычисляемом выражении:

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

Я думал об использовании std::is_constant_evaluated: компилятора-проводника

#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, но я ее не нашел.

Есть ли какой-нибудь трюк, чтобы получить ошибку времени компиляции в выражении, которое можно было бы вычислить константой?


person Oliv    schedule 06.01.2020    source источник
comment
static_assert оценивается во время компиляции. Следовательно, проверяемое выражение должно быть constexpr, а не просто const. И в этом проблема: компиляция вашей функции compile_time_error function всегда будет терпеть неудачу.   -  person Rene    schedule 06.01.2020
comment
Просто используйте runtime_error(). Это вызовет ошибку, если будет вычислено во время компиляции.   -  person cpplearner    schedule 06.01.2020


Ответы (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);
}

Однажды я написал библиотеку в CI под названием curb, который сделал бы что-то вроде этого.

person KamilCuk    schedule 06.01.2020
comment
GCC по-прежнему соблюдает контракт постоянной инициализации и вместо этого выполняет обычную инициализацию godbolt.org/z/afrvEM - person StoryTeller - Unslander Monica; 06.01.2020
comment
Спасибо! На самом деле он работает только с __builtin_constant_p, а не с is_constant_evaluate(). - person Oliv; 06.01.2020
comment
Гарантирует ли это стандартную ошибку или это обычное поведение? - person M.M; 06.01.2020
comment
В стандарте о __builtin_constant_p нет ничего. Это частный вызов gcc. Следовательно, не гарантируется ни работа, ни обычное поведение. Но он ДОЛЖЕН работать для текущих версий gcc. - person Marshall Clow; 06.01.2020
comment
Обратите внимание, что этот ответ не зависит от того, является ли Assert(false) (частью) константным выражением; он срабатывает, если аргумент известен компилятору (возможно, из-за оптимизации). - person Davis Herring; 08.01.2020