Ранее я спрашивал о перегрузке функций на основе того, являются ли аргументыconstexpr
. Я пытаюсь обойти неутешительный ответ на этот вопрос, чтобы сделать более умную функцию утверждения. Это примерно то, что я пытаюсь сделать :
inline void smart_assert (bool condition) {
if (is_constexpr (condition))
static_assert (condition, "Error!!!");
else
assert (condition);
}
. По сути, идея состоит в том, что проверка во время компиляции -всегда лучше, чем проверка во время выполнения -, если это возможно проверить во время компиляции. Однако из-за таких вещей, как встраивание и свертывание констант, я не всегда могу знать, возможна ли проверка во время компиляции. Это означает, что могут быть случаи, когда assert (condition)
компилируется в assert(false)
, и код просто ждет, пока я его запущу и выполню этот путь, прежде чем я обнаружу ошибку.
Поэтому, если бы был какой-то способ проверить, является ли условие constexpr (из-за встраивания или других оптимизаций ), я мог бы вызвать static_assert
, когда это возможно, и вернуться к времени выполнения -утверждать обратное. К счастью, gcc имеет встроенную функцию __builtin_constant_p (exp)
, которая возвращает true, если exp
является constexpr. Я не знаю, есть ли у других компиляторов эта встроенная функция, но я надеялся, что это решит мою проблему. Это код, который я придумал:
#include
#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
игнорируется, поэтому я просто получаю оператор (run -time assert
(, который терпит неудачу ). Однако
[david@david-desktop 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
)? Я чувствую, что мои проекты на C++ теоретически могли бы значительно выиграть от более умного оператора assert, который перехватывает ошибки как можно раньше.
Не похоже, что превращение smart_assert
функции -в виде макроса не решит проблему в общем случае. Очевидно, что это заставит его работать в этом простом примере, но condition
может исходить из функции двумя уровнями выше графа вызовов (, но все равно становится известным компилятору как constexpr
из-за встраивания ), которое сталкивается с той же проблемой использования параметра функции в static_assert
.