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

Pas*_* By 9 c++ static-assert language-lawyer

提供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>>>
{
    // ...
};
Run Code Online (Sandbox Code Playgroud)

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

第二个static_assert显然是一个重言式,但它"取决于" T,以达到预期的效果.但这有保证吗?是否允许编译器评估这些重言式?

Bar*_*rry 9

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

知道哪些名称是类型名称允许检查每个模板的语法.如果出现以下情况,该计划格式错误,无需诊断:

  • 无法为模板或模板中的constexpr if语句的子语句生成有效的特化,并且模板未实例化,或者

  • [...]

static_assert示例中的两个s都会导致程序格式错误,但不需要诊断.当然,允许编译器评估任意复杂的表达式,以试图证明不能生成有效的特化,但并不要求它们这样做.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");
};
Run Code Online (Sandbox Code Playgroud)

always_false可以假设专门针对特定T产量true_type,因此可以假设有效的专业化S<T>.但是不要让任何人真正这样做.

  • 等等,_"没有为模板生成有效的专门化"_,不是指"没有`T`存在使得`S <T>`有效"?但在示例中,`S <int>`是有效的,因此程序格式正确? (2认同)