Narzędzia użytkownika

Narzędzia witryny


static_assert

Biblioteka Boost Static Assert

Biblioteka Boost Static Assert udostępnia pojedyncze makro o nazwie BOOST_STATIC_ASSERT. Makro to jest analogiczne do popularnego makra assert ze standardowej biblioteki języka C z tą jednak podstawową różnicą, że działa w czasie kompilacji kodu, a nie jego wykonania. W przypadku, gdy wartość wyrażenia podanego jako argument makra jest fałszem, BOOST_STATIC_ASSERT powoduje błąd kompilacji. Należy zaznaczyć, że wartość argumentu makra musi dać się obliczyć w trakcie kompilacji, żeby makro zadziało. W związku z tym poniższa konstrukcja zakończy się błędem kompilacji (i to bynajmniej nie wywołanym intencjonalnie przez BOOST_STATIC_ASSERT):

void funcWithI() {
   int i = 5;
   BOOST_STATIC_ASSERT(i > 0); // błąd - wartość i nieznana podczas kompilacji
 
   //...
}

W powyższym kodzie powinno zostać użyte makro assert, gdyź ewidentnie chcemy sprawdzić wartość dostępną jedynie w czasie działania programu.

Makro BOOST_STATIC_ASSERT można umieścić wszędzie tam, gdzie ,można umiesczać deklaracje, a więc w przestrzeniach nazw, w klasach, funkcjach.

BOOST_STATIC_ASSERT w przestrzeniach nazw

BOOST_STATIC_ASSERT w zasięgu przestrzeni nazw jest użyteczne, gdy chcemy sprawdzić, czy platforma, na której dokonywana jest kompilacja naszego programu spełnia określone wymagania. Poniżej chcemy zagwarantować, że platforma, dla której kompilujemy kod ma typ unsigned long int długości co najmniej 32 bitów.

namespace boost_static_assert_space {
   BOOST_STATIC_ASSERT(sizeof(unsigned long int) >= 4);
}

BOOST_STATIC_ASSERT w zasięgu funkcji

Użycie makra z biblioteki Boost jest również (a może nawet bardziej) przydatne w zasięgu generycznych funkcji, do sprawdzania parametrów szablonu. Poniżej przykład funkcji liczącej silnię, która akceptuje jedynie liczby całkowite bez znaku (dla innych silnia jest niezdefiniowana):

template<typename T> T factorial(T arg) {
   BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed);
 
   T result = T(1);
   if (arg > T(0))
      while (arg > T(0)) {
         result *= arg;
         --arg;
      }
   return result;
}

Uwaga do powyższego przykładu: Oczywiście możemy np. zaimplementować klasę, która będzie „udawać” liczbę całkowitą bez znaku o nieograniczonej ilości bitów (przeciążając odpowiednie operatory) i wyspecjalizować klasę std::numeric_limits, by poprzez is_integer zwracała true, a przez is_signed false dla naszego nowego typu. To pozwoli używać powyższej funkcji dla naszych „spreparowanych” liczb.

BOOST_STATIC_ASSERT w zasięgu klasy

Makra BOOST_STATIC_ASSERT można używać również w zasięgu klasy. Najbardziej przydaje się to znów w przypadku szablonów, gdyż pozwala upewnić się, że argument szablonu spełnia stawiane przed nim wymagania, których inaczej nie dałoby się sprawdzić podczas kompilacji. Poniżej znajduje się przykład klasy implementującej teksturę dla potrzeb grafiki, gdzie użyto bardzo wydajnych algorytmów, które mają jednak to ograniczenie, że działają tylko gdy rozmiary tekstury są potęgą liczby 2:

template<unsigned int SIZE> class SquareOldStyleTexture {
   BOOST_STATIC_ASSERT((SIZE & (SIZE - 1)) == 0);
public:
   inline unsigned int getSize() { return SIZE; }
};

Uwagi końcowe

Makro BOOST_STATIC_ASSERT pozwala wychwycić błędne (nizamierzone) użycia szablonów, bądź mechanizmów zanim objawią się awarią działającej aplikacji. Ma jednak przynajmniej dwie wady:

  • nie można przekazać żadnego komunikatu dotyczącego błędu asercji.
  • błąd asercji pojawia się w linii, w której użyto makra, a nie w linii w której występuje deklaracja, bądź wywołanie, które spowodowało ten błąd.

Powyższe dwie rzeczy sprawiają, że BOOST_STATIC_ASSERT jest dosyć niewygodny w użyciu, gdyż czasami może być ciężko zlokalizować bezpośrednią przyczynę błędu kompilacji.

Pełny przykładowy program, pozwalający wywołać również błędy kompilacji w wyniku niespełnionej asercji, a także zawierający niniejsze komentarze znajduje się w pliku boost_static_assert.cpp.

static_assert.txt · ostatnio zmienione: 2009/04/04 22:55 przez mlech1