constexpr, static_assert i inlining
Wcześniej pytałem oprzeciążenie funkcji na podstawie tego, czy argumenty sąconstexpr
. Próbuję obejść rozczarowującą odpowiedź na to pytanie, aby stworzyć mądrzejszą funkcję asercji. To jest mniej więcej to, co próbuję zrobić:
<code>inline void smart_assert (bool condition) { if (is_constexpr (condition)) static_assert (condition, "Error!!!"); else assert (condition); } </code>
Zasadniczo chodzi o to, że sprawdzanie w czasie kompilacji jest zawsze lepsze niż sprawdzanie w czasie wykonywania, jeśli możliwe jest sprawdzenie w czasie kompilacji. Jednak ze względu na takie rzeczy, jak wstawianie i ciągłe składanie, nie zawsze wiem, czy możliwe jest sprawdzenie czasu kompilacji. Oznacza to, że mogą wystąpić przypadkiassert (condition)
kompiluje doassert(false)
a kod tylko czeka, aż go uruchomię i wykonam tę ścieżkę, zanim stwierdzę, że wystąpił błąd.
Dlatego, jeśli był jakiś sposób, aby sprawdzić, czy warunek jest constexpr (z powodu wstawiania lub innych optymalizacji), mógłbym zadzwonićstatic_assert
kiedy to możliwe, i wycofać się w czasie run twierdzą inaczej. Na szczęście gcc ma wewnętrzną__builtin_constant_p (exp)
, która zwraca wartość true, jeśliexp
jest constexpr. Nie wiem, czy inne kompilatory mają to samo, ale miałem nadzieję, że to rozwiąże mój problem. Oto kod, który wymyśliłem:
<code>#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 </code>
Thestatic_assert
polega na zwarciuor
. JeśliIS_CONSTEXPR
to prawdastatic_assert
może być używany, a warunek jest!true or condition
, który jest taki sam jak po prostucondition
. JeśliIS_CONSTEXPR
jest więc fałszywestatic_assert
nie można użyć, a warunek jest!false or condition
, który jest taki sam jaktrue
istatic_assert
jest ignorowany. Jeślistatic_assert
nie można sprawdzić, ponieważcondition
nie jest constexpr, a następnie dodaje czas wykonywaniaassert
do mojego kodu jako ostatni wysiłek. Jednak to nie działabrak możliwości użycia argumentów funkcji w astatic_assert
, nawet jeśli argumenty sąconstexpr
.
W szczególności dzieje się tak, gdy próbuję skompilować z gcc:
<code>// main.cpp int main () { smart_assert (false); return 0; } </code>
g++ main.cpp -std=c++0x -O0
Wszystko jest w porządku, kompiluje się normalnie. Nie ma wstawiania bez optymalizacji, więcIS_CONSTEXPR
jest fałszywe istatic_assert
jest ignorowany, więc po prostu otrzymuję czas wykonaniaassert
oświadczenie (to się nie udaje). Jednak,
<code>[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 </code>
Jak tylko włączę wszelkie optymalizacje i tym samym potencjalnie pozwolęstatic_assert
aby zostać uruchomionym, zawodzi, ponieważ nie mogę użyć argumentów funkcji wstatic_assert
. Czy jest jakiś sposób na obejście tego problemu (nawet jeśli oznacza to wdrożenie własnegostatic_assert
)? Uważam, że moje projekty C ++ mogą teoretycznie przynieść spore korzyści z inteligentniejszego stwierdzenia assert, które wychwytuje błędy tak szybko, jak to możliwe.
To nie wygląda na robieniesmart_assert
makro podobne do funkcji rozwiąże problem w ogólnym przypadku. Będzie to oczywiście działać w tym prostym przykładzie, alecondition
może pochodzić z funkcji dwóch poziomów wykresu wywołania (ale nadal staje się znana kompilatorowi jakoconstexpr
z powodu wstawiania), który napotyka ten sam problem z użyciem parametru funkcji w astatic_assert
.