Statyczna asercja
funus.net
Statyczna asercja (ang. static assert) to konstrukcja w języku C++, której zadaniem jest sprawdzenie podczas kompilacji pewnych założeń. Zastosowanie jest podobne, jak makra assert() z biblioteki standardowej, może jedak sprawdzać tylko takie warunki, których wartość logiczną da się wyznaczyć na etapie kompilacji.
Typowym zastosowaniem statycznej asercji może być sprawdzanie założeń programisty co do rozmiaru obiektu danego typu. Co prawda można w tym celu zastosować maro assert(), np. tak:
assert(sizeof(int) == sizeof(long));
ma ono jednak tę wadę, że niespełnienie warunku objawi się dopiero podczas wykonania programu, powodując jego awaryjne przerwanie. W dodatku może się zdarzyć, że podczas testów sterowanie akurat nie trafi w dane miejsce i błąd nie zostanie wykryty.
W przypadku asercji statycznej, program niespełniający warunku po prostu nie zostanie skompilowany, gwarantując, że tego typu błędy nie umkną uwadze programistów.
Standardowy C++ nie posiada wbudowanej konstrukcji typu statyczna asercja. Można jednak wykorzystać np. bibliotekę boost bądź bez trudu stworzyć odpowiednie makro samemu.
[edytuj] Przykładowa implementacja
Implementacja opiera się na metaprogramowaniu szablonowym (ang. template metaprogramming) i ─ jak sama nazwa wskazuje ─ wykorzystuje szablony (wzorce) języka C++.
static_assert.h:
template <bool>
class static_assert_tmpl;
template <>
class static_assert_tmpl<true>
{ };
#define STATIC_ASSERT(cond) static_assert_tmpl<cond>()
W powyższym fragmencie zadeklarowano szablon klasy static_assert_tmpl, sparametryzowany wartością typu bool. Co istotne, nie ma definicji tego szablonu, tylko sama deklaracja. Drugim elementem jest całkowita specjalizacja szablonu static_assert_tmpl, dla wartości logicznej true. Tym razem konieczna jest definicja klasy (wystarczy pusta). Dla wygody i uzyskania notacji w stylu wywołania funkcji, zdefiniowano też makro STATIC_ASSERT().
Przykład wykorzystania z warunkiem, który powinien zawsze być spełniony:
#include "static_assert.h"
int main(int, char**)
{
STATIC_ASSERT(sizeof(char) == 1);
}
Ponieważ z definicji rozmiar danej typu char wynosi 1, program skompiluje się bez żadnego problemu.
Przykład niespełnionego warunku:
#include "static_assert.h"
int main(int, char**)
{
STATIC_ASSERT(2 * 2 == 5);
}
Próba skompilowania powyższego programu za pomocą gcc nie powiedzie się, wypisane zostaną mniej więcej takie komunikaty:
sample.cc: In function 'int main(int, char**)': sample.cc:5: error: invalid use of undefined type 'struct static_assert_tmpl<false>' static_assert.h:3: error: declaration of 'struct static_assert_tmpl<false>'
Jak widać, działanie tej implementacji statycznej asercji opiera się na tym, że nie ma definicji szablonu klasy static_assert_tmpl, jest jedynie definicja jego specjalizacji dla wartości logicznej true. Fałszywy warunek sprawdzony przy pomocy makra STATIC_ASSERT() spowoduje więc wygenerowanie odwołania do klasy, której definicja nie istnieje, i w konsekwencji błąd kompilacji. Natomiast warunek prawdziwy skorzysta ze specjalizacji static_assert_tmpl<true>, dzięki czemu skompiluje się bez żadnego problemu.
[edytuj] Standaryzacja
W C++0x static_assert jest częścią biblioteki standardowej.
