ядро языка · синтаксисcore language · syntax
Проверка константного условия на этапе компиляции с собственным сообщением об ошибке. Если условие ложно — компиляция останавливается до генерации какого-либо кода, а не при первом запуске программы.A compile-time check of a constant condition with its own error message. If the condition is false, compilation stops before any code is generated, rather than the first time the program is run.
static_assert(константное_выражение, "сообщение"); — декларация, проверяющая булево константное выражение на этапе компиляции. Если выражение ложно, компилятор выдаёт ошибку с указанным сообщением и прекращает компиляцию единицы трансляции; если истинно — декларация не порождает вообще никакого кода.static_assert(constant_expression, "message"); is a declaration that checks a boolean constant expression at compile time. If the expression is false, the compiler emits an error with the given message and stops compiling the translation unit; if true, the declaration produces no code whatsoever.
// трюк через массив отрицательного размера —// a trick using a negative-size array —
// нечитаемое сообщение об ошибке// an unreadable error message
#define STATIC_ASSERT(cond) \
typedef char static_assertion[(cond) ? 1 : -1]
STATIC_ASSERT(sizeof(int) == 4);
static_assert(sizeof(int) == 4,
"код рассчитан на 32-битный int""code assumes a 32-bit int");
До C++11 compile-time проверки существовали только в виде хаков поверх шаблонов и препроцессора:Before C++11, compile-time checks existed only as hacks built on top of templates and the preprocessor:
Классический способ проверки условия на этапе компиляции — typedef char x[cond ? 1 : -1] — давал нечитаемую ошибку компилятора без пояснения сути проблемы. static_assert решает ту же задачу штатным средством языка с человекочитаемым сообщением.The classic way to check a condition at compile time — typedef char x[cond ? 1 : -1] — produced an unreadable compiler error with no explanation of the actual problem. static_assert solves the same task as a first-class language facility with a human-readable message.
Библиотеки шаблонов получили способ явно ограничить допустимые типы параметров (например, «T должен быть тривиально копируемым») с понятным сообщением вместо страницы нечитаемых ошибок вывода типов вглубь реализации.Template libraries gained a way to explicitly constrain the allowed parameter types (for example, "T must be trivially copyable") with a clear message, instead of a page of unreadable type-deduction errors buried deep in the implementation.
Размеры типов, выравнивание структур, поддержка нужных фич компилятором — всё это можно и нужно проверять при компиляции, а не через assert() в рантайме, который сработает только если код вообще будет запущен на этой платформе.Type sizes, struct alignment, compiler support for required features — all of this can and should be checked at compile time, rather than through a runtime assert() that only fires if the code is ever actually run on that platform.
static_assert — не функция и не макрос, а декларация языка, обрабатываемая компилятором на этапе семантического анализа. Условие обязано быть constant expression — вычислимым во время компиляции (литералы, constexpr-функции, значения шаблонных параметров, результаты sizeof/type_traits). При успехе — декларация полностью исчезает, не оставляя ни кода, ни данных в бинарнике; при провале — компиляция останавливается на этой единице трансляции.static_assert is neither a function nor a macro — it's a language declaration processed by the compiler during semantic analysis. The condition must be a constant expression, computable at compile time (literals, constexpr functions, template parameter values, results of sizeof/type_traits). On success, the declaration vanishes entirely, leaving neither code nor data in the binary; on failure, compilation halts for that translation unit.
#include <type_traits>
template <class T>
class Buffer {
static_assert(std::is_trivially_copyable<T>::value,
"Buffer<T> требует тривиально копируемый T""Buffer<T> requires a trivially copyable T");
// ...// ...
};
struct Packet {
std::uint32_t id;
std::uint16_t size;
};
static_assert(sizeof(Packet) == 6, "неожиданный padding в Packet""unexpected padding in Packet");
// с C++17 сообщение можно опустить:// with C++17 the message can be omitted:
// static_assert(sizeof(Packet) == 6);
Проверка значения переменной времени выполнения (например, аргумента функции) в static_assert не скомпилируется — это не constant expression. Частая путаница у новичков, ожидающих поведения как у рантайм-assert().Checking the value of a runtime variable (say, a function argument) in a static_assert won't compile — it isn't a constant expression. A common point of confusion for newcomers expecting behavior like the runtime assert().
В C++11 второй аргумент — строковый литерал — обязателен; static_assert(cond) без сообщения не скомпилируется до C++17. При написании переносимого на C++11 кода про это легко забыть, ориентируясь на более новые примеры.In C++11, the second argument — a string literal — is required; static_assert(cond) without a message doesn't compile until C++17. It's easy to forget this when writing C++11-portable code while working from more modern examples.
Если условие зависит от параметра шаблона T, static_assert не сработает, пока шаблон не инстанцирован с конкретным типом — ошибка не обнаружится, пока никто не создаст экземпляр с «плохим» T, что может случиться далеко от места объявления шаблона.If the condition depends on the template parameter T, the static_assert won't fire until the template is instantiated with a concrete type — the error stays hidden until someone creates an instance with a "bad" T, which can happen far away from where the template was declared.