Макрос вызывает этот код следующим образом:
compile_time_check<static expression> temp(Error_Some_Struct_here);
Так, например, вы можете сделать это:
compile_time_check<sizeof(Foo) < sizeof(Bar)> temp(Error_Foo_must_be_smaller_than_Bar);
Когда sizeof(Foo)
меньшеsizeof(Bar)
, шаблон будет создавать неспециализованную версию:
template<bool> class compile_time_check
{
public:
compile_time_check(...) {} //What is this?
};
, а код в основном "компилируется" в экземпляр этого класса:
compile_time_check temp(Error_Foo_must_be_smaller_than_Bar);
, который, будучи пустым и выполняющимничего, компилятор может удалить как мертвый код.Бэм, никаких накладных расходов во время выполнения, готово.
Если, с другой стороны, sizeof(Foo)
больше или равно sizeof(Bar)
, вместо этого будет создана специализированная версия:
template<> class compile_time_check<false>
{
};
и он попытается вызвать конструктор compile_time_check::compile_time_check(struct)
, но поскольку он не существует, это ошибка компиляции.Это именно то, что вам нужно, потому что статическое утверждение должно компилироваться только в том случае, если утверждение истинно.
Причина, по которой конструктор принимает список параметров с переменными параметрами, я полагаю, двойная:
- Чтобы убедиться, что он не вызывает конструктор по умолчанию, который имел бы специализированная версия.Его переменная, так что вы можете передать в любой структуре как «строку» ошибки.В качестве альтернативы, это могло быть шаблонно, и конструктор мог бы вместо этого взять объект шаблона в качестве аргумента.
- , чтобы можно было передать сообщение об ошибке. Когда утверждение равно true, это игнорируется, и ничего не происходит, икод удаляется оптимизатором компиляторов.Если assert ложно, однако, строка ошибки должна появиться в сообщении об ошибке.Что-то вроде
constructor not found for compile_time_check::compile_time_check(ERROR_Assertion_error_blah())
возможно.
Альтернативный, без шаблонов (я полагаю, его часто используют в C) статический assert, который я видел где-то раньше, это:
#define compile_time_assert(pred) switch(0){case: 0: case pred:;}
Это работает, потому что если pred
равно false, код будет иметь вид switch(0){case: 0: case 0:;}
, а две метки регистра с одинаковой константой будут ошибкой. Подробное объяснение здесь .