Static assert to mechanizm kompilatora do generowania błędów na etapie kompilacji, jeśli wyrażenie (warunek) nie jest spełnione. Funkcjonalność ta została wprowadzona od C++11, aby ułatwić programowanie szablonów i poprawić jakość kodu.
Historia zagadnienia.
Przed pojawieniem się static_assert programiści używali sztuczek, takich jak struktury z ujemnym rozmiarem tablicy (np. char arr[condition?1:-1];), co było mniej czytelne i mniej wygodne do diagnostyki błędów. Tak zrodziła się potrzeba jawnej deklaracji błędów czasu kompilacji z sensownym komunikatem.
Problem.
W programowaniu szablonowym często pojawia się potrzeba wczesnej diagnostyki (np. zakaz tworzenia obiektu z nieodpowiednim typem lub parametrem). Bez statycznej kontroli takie błędy pojawiały się dopiero na etapie kompilacji końcowego kodu (czasami jako nagła i słabo wyjaśniona pomyłka).
Rozwiązanie.
Słowo kluczowe static_assert przyjmuje wyrażenie boolowskie i ciąg komunikatu. Jeśli wyrażenie jest fałszywe, kompilacja zakończy się błędem z komunikatem.
Przykład kodu:
static_assert(sizeof(int) >= 4, "int musi mieć co najmniej 4 bajty"); template<typename T> void foo(const T& obj) { static_assert(std::is_copy_constructible<T>::value, "T musi być konstrukowalne kopiowo"); }
Kluczowe cechy:
Czy można używać static_assert bez drugiego argumentu?
Tak, począwszy od C++17 drugi argument jest opcjonalny:
static_assert(sizeof(double) == 8); // komunikat będzie domyślny
Czy wyrażenia static_assert są wykonywane, jeśli warunek zależy od parametrów szablonu, ale szablon nie jest instancjowany?
Nie, static_assert wyzwala się tylko wtedy, gdy osiąga punkt instancjacji, co pozwala stosować kontrole tylko dla używanych szablonów.
Czy można używać wyrażeń czasu wykonywania (run-time) wewnątrz static_assert?
Nie, wyrażenie musi być obliczalne na etapie kompilacji (constexpr). Jeśli wyrażenie nie jest constexpr — wystąpi błąd kompilacji.
W kodzie używano static_assert z wyrażeniem obliczanym tylko w czasie działania (np. rozmiar pliku przy odczycie danych), co spowodowało niejasny błąd kompilacji w całym systemie.
Zalety:
Wady:
Należy zagwarantować, że szablon Matrix może być tworzony tylko z typami Plain Old Data (POD), wykluczając złożone struktury.
template<typename T> class Matrix { static_assert(std::is_pod<T>::value, "Matrix może być instancjonowana tylko dla typów POD"); // ... };
Zalety:
Wady: