constexpr, static _assert и встраивание

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

13
задан Community 23 May 2017 в 11:47
поделиться