ядро языка · синтаксисcore language · syntax

static_assert

Проверка константного условия на этапе компиляции с собственным сообщением об ошибке. Если условие ложно — компиляция останавливается до генерации какого-либо кода, а не при первом запуске программы.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.

часто используетсяcommonly used нулевой рантайм-overheadzero runtime overhead

Что этоWhat it is

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.

до C++11before C++11
// трюк через массив отрицательного размера —// 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_assertwith static_assert
static_assert(sizeof(int) == 4,
    "код рассчитан на 32-битный int""code assumes a 32-bit int");

Зачем ввелиWhy it was introduced

До C++11 compile-time проверки существовали только в виде хаков поверх шаблонов и препроцессора:Before C++11, compile-time checks existed only as hacks built on top of templates and the preprocessor:

01

Заменить трюки на массивы отрицательного размераReplace negative-size array tricks

Классический способ проверки условия на этапе компиляции — 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.

02

Проверка инвариантов шаблонов до инстанцированияChecking template invariants before instantiation

Библиотеки шаблонов получили способ явно ограничить допустимые типы параметров (например, «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.

03

Проверка платформенных допущенийVerifying platform assumptions

Размеры типов, выравнивание структур, поддержка нужных фич компилятором — всё это можно и нужно проверять при компиляции, а не через 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.

Как это работает под капотомHow it works under the hood

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);

ГраблиGotchas

Условие обязано быть вычислимо на этапе компиляцииThe condition must be computable at compile time

Проверка значения переменной времени выполнения (например, аргумента функции) в 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 (опционально с C++17)The message is mandatory in C++11 (optional since C++17)

В 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.

static_assert внутри шаблона проверяется только при инстанцированииA static_assert inside a template is only checked on instantiation

Если условие зависит от параметра шаблона 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.