是否允许编译器在静态断言中评估重言式

Are compilers allowed to evaluate tautologies in static assert

本文关键字:断言 评估 重言式 静态 编译器 是否      更新时间:2023-10-16

在模板中提供static_assert通常很有帮助。在模板根本不应该以某种方式实例化的情况下,我经常这样做

template<typename T, typename = void>
struct S
{
static_assert(false, "Unconditional error");
static_assert(sizeof(T) != sizeof(T), "Error on instantiation");
};
template<typename T>
struct S<T, std::enable_if_t<std::is_integral_v<T>>>
{
// ...
};

即使没有实例化S,第一个static_assert也会立即失败,而如果没有实例化将导致主模板,则第二个将成功。

第二static_assert显然是重言式,但它"取决于"T才能达到预期的效果。但这能保证吗?编译器是否可以评估这些重言式?

相关规则是 [temp.res]/8:

知道哪些名称是类型名称可以检查每个模板的语法。程序格式不正确,无需诊断,如果:

  • 无法为模板或 constexpr 的子语句生成有效的专用化,如果模板中的语句未实例化,则模板未实例化,或者

  • [...]

示例中的两个static_assert都会导致程序格式不正确,但不需要诊断。编译器当然可以计算任意复杂的表达式,以尝试证明无法生成有效的专用化,但并不要求他们这样做。false当然是一个容易立即验证的情况,所以它被诊断出来也就不足为奇了。


希望始终发出诊断的常见方法是:

// never specialize me!
template <typename T>
struct always_false : std::false_type { };
template <typename T>
constexpr bool always_false_v = always_false<T>::value;
template<typename T, typename = void>
struct S {
static_assert(always_false_v<T>, "Unconditional error");
};

always_false可以假设地专门化于特定的T以产生true_type,所以假设可能存在一个有效的专业化S<T>。但不要让任何人真正这样做。