Я ранее спрашивал о перегрузке функции на основе аргументов constexpr
. Я пытаюсь обойти неутешительный ответ на этот вопрос, чтобы сделать более умную функцию утверждения. Это примерно то, что я пытаюсь сделать:
inline void smart_assert (bool condition) {
if (is_constexpr (condition))
static_assert (condition, "Error!!!");
else
assert (condition);
}
В принципе, идея состоит в том, что проверка времени компиляции всегда лучше проверки времени выполнения, если ее можно проверить во время компиляции. Однако из-за таких вещей, как inlining и постоянное складывание, я не всегда знаю, возможна ли проверка времени компиляции. Это означает, что могут быть случаи, когда assert (condition)
скомпилируется до assert(false)
, и код просто ждет, когда я запустим его и выполнит этот путь до того, как я узнаю, что есть ошибка.
Следовательно, если бы был какой-то способ проверить, является ли условие constexpr (из-за вложения или других оптимизаций), я мог бы по возможности называть static_assert
и отказываться от времени выполнения в противном случае. К счастью, gcc имеет встроенный __builtin_constant_p (exp)
, который возвращает true, если exp
является constexpr. Я не знаю, есть ли у других компиляторов это внутреннее, но я надеялся, что это решит мою проблему. Это код, который я придумал:
#include <cassert>
#undef IS_CONSTEXPR
#if defined __GNUC__
#define IS_CONSTEXPR(exp) __builtin_constant_p (exp)
#else
#define IS_CONSTEXPR(exp) false
#endif
// TODO: Add other compilers
inline void smart_assert (bool const condition) {
static_assert (!IS_CONSTEXPR(condition) or condition, "Error!!!");
if (!IS_CONSTEXPR(condition))
assert (condition);
}
#undef IS_CONSTEXPR
static_assert
полагается на поведение короткого замыкания or
. Если IS_CONSTEXPR
истинно, тогда можно использовать static_assert
, а условие !true or condition
, что совпадает с просто condition
. Если IS_CONSTEXPR
является ложным, то static_assert
не может использоваться, и условие !false or condition
, которое равно как и true
, а static_assert
игнорируется. Если параметр static_assert
не может быть проверен, потому что condition
не является constexpr, я добавляю во время выполнения assert
в мой код как последнее действие. Однако это не работает, благодаря неспособности использовать аргументы функции в static_assert
, даже если аргументы constexpr
.
В частности, это то, что происходит, если я пытаюсь скомпилировать с помощью gcc:
// main.cpp
int main () {
smart_assert (false);
return 0;
}
g++ main.cpp -std=c++0x -O0
Все нормально, компилируется нормально. Нет никакой вставки без оптимизации, поэтому IS_CONSTEXPR
является ложным, а static_assert
игнорируется, поэтому я просто получаю инструкцию assert
(которая не работает). Тем не менее,
[[email protected] test]$ g++ main.cpp -std=c++0x -O1
In file included from main.cpp:1:0:
smart_assert.hpp: In function ‘void smart_assert(bool)’:
smart_assert.hpp:12:3: error: non-constant condition for static assertion
smart_assert.hpp:12:3: error: ‘condition’ is not a constant expression
Как только я включу какие-либо оптимизации и, возможно, разрешу запуск static_assert
, он терпит неудачу, потому что я не могу использовать аргументы функции в static_assert
. Есть ли способ обойти это (даже если это означает реализацию моего собственного static_assert
)? Я чувствую, что мои проекты на С++ теоретически могут принести пользу от более умного утверждения assert, который как можно раньше обнаруживает ошибки.
Кажется, что создание smart_assert
функционального макроса решит проблему в общем случае. Очевидно, что это будет работать в этом простом примере, но condition
, возможно, исходит из функции на два уровня вверх по графику вызовов (но все равно становится известен компилятору как constexpr
из-за вложения), который работает в том же проблема использования параметра функции в static_assert
.