为什么模板中的static_assert会给出与等价表达式不同的结果?

问题描述:

我注意到 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的bug?那么,gcc是正确的?

to give me same result, but it causes static assertion failure: http://ideone.com/UEu9Kv . Is gcc correct in both cases? If so, why? Or is it a gcc bug? Then, in which case gcc is correct?

§14.6[temp.res] / p8:

§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 而不是另一个)(当你使用 D& ; 0 )。

In both cases no valid specialization can be generated for the primary template due to the static_assert (D && 0 is never true no matter the value of D). Since no diagnostic is required, the compiler is free to diagnose one (when you use 0) but not the other (when you use 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_false 成员为 true

The compiler can no longer reject this at definition time, as there might be an explicit specialization of always_false whose value member is true.