Ранее я спросил о function overloading based on whether the arguments are constexpr
. Я пытаюсь обойти неутешительный ответ на этот вопрос, чтобы сделать более умную функцию утверждения. Это примерно то, что я пытаюсь сделать:constexpr, static_assert и inlining
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
в мой код как последнее усилие. Однако это не работает, благодаря not being able to use function arguments in a static_assert
, even if the arguments are 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
)? Я чувствую, что мои проекты на C++ теоретически могут принести пользу от более умного утверждения assert, который как можно раньше уловляет ошибки.
Это не похоже на создание smart_assert
Функциональный макрос решит проблему в общем случае. Очевидно, что он будет работать в этом простом примере, но condition
, возможно, пришел из функции на два уровня вверх по графику вызовов (но все равно становится известен компилятору как constexpr
из-за inlining), который сталкивается с той же проблемой использования параметр функции в static_assert
.
можно написать макрос, который определяет, является ли выражение константы в стандартном C++ –
@ JohannesSchaub-LITB не будет ли такой макрос необходимость расширения для определения класса ? Это не будет использоваться внутри функции 'constexpr'. – Potatoswatter
@pot, зачем ему нужно расширять до определения класса? –