Я ранее спрашивал о перегрузке функции на основе аргументов 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.