为什么模板中的 static_assert 使用等效表达式会给我不同的结果?

Why static_assert in template gives me different result with equivalent expressions?

我注意到 static_assert 的奇怪行为:

#include <iostream>

template <typename T, unsigned int D> struct Vec
{
    static_assert(D && 0, "Invalid dimension for vector!");
};

template <typename T> struct Vec<T, 1>             {union {T x, r;};};
template <typename T> struct Vec<T, 2> : Vec<T, 1> {union {T y, g;};};
template <typename T> struct Vec<T, 3> : Vec<T, 2> {union {T z, b;};};
template <typename T> struct Vec<T, 4> : Vec<T, 3> {union {T w, a;};};

int main()
{
    Vec<float, 3> v;
    v.x = 1;
    v.y = 2;
    v.z = 3;

    return 0;
}

它编译得很好:http://ideone.com/wHbJYP。我希望

static_assert(0, "Invalid dimension for vector!");

给我相同的结果,但它会导致静态断言失败:http://ideone.com/UEu9Kv。 gcc 在这两种情况下都正确吗?如果是这样,为什么?或者它是一个 gcc 错误?那么,gcc在什么情况下是正确的呢?

§14.6 [temp.res]/p8:

If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required.

在这两种情况下,由于 static_assert(无论 D 的值如何,D && 0 都不会为主模板生成有效的特化。由于不需要诊断,因此编译器可以自由诊断一个(当您使用 0 时)而不是另一个(当您使用 D && 0 时)。

解决方法:

template <unsigned int D> struct always_false : std::false_type {};

template <typename T, unsigned int D> struct Vec
{
    static_assert(always_false<D>::value, "Invalid dimension for vector!");
};

编译器在定义时不能再拒绝它,因为 always_falsevalue 成员可能是 true.

的显式特化

所有不是 1、2、3、4 的东西(存在特定的专业化)都将进入 "master" 定义,必须为 D 的每个值断言它将被调用。

因此您需要一个包含 D 始终为 false 的表达式,以使编译器对其求值 依赖于D

如果您只使用 0,它将不再依赖,并且编译器将在解析过程中评估它是否匹配,从而导致断言始终发生。即使它不是您要实例化的 class。