c++ - primaria - ¿Por qué static_assert en la plantilla me da resultados diferentes con expresiones equivalentes?
fracciones equivalentes (2)
He notado un comportamiento extraño de 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;
}
Compila bien: http://ideone.com/wHbJYP . Yo esperaría
static_assert(0, "Invalid dimension for vector!");
para darme el mismo resultado, pero causa una falla de aserción estática: http://ideone.com/UEu9Kv . ¿Es correcto el gcc en ambos casos? Si es así, ¿por qué? ¿O es un error de gcc? Entonces, ¿en qué caso gcc es correcto?
§14.6 [temp.res] / p8:
Si no se puede generar una especialización válida para una plantilla, y esa plantilla no se crea una instancia, la plantilla está mal formada, no se requiere diagnóstico.
En ambos casos, no se puede generar una especialización válida para la plantilla primaria debido a la static_assert
( D && 0
nunca es verdadera, sin importar el valor de D
). Como no se requiere diagnóstico, el compilador puede diagnosticar uno (cuando usa 0
) pero no el otro (cuando usa D && 0
).
Solución:
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!");
};
El compilador ya no puede rechazar esto en el momento de la definición, ya que puede haber una especialización explícita de always_false
cuyo value
member sea true
.
Todo lo que no es 1,2,3,4 (para lo que existen especializaciones específicas) irá a la definición "maestra", que debe afirmarse para cada valor de D que se llamará.
Por lo tanto, necesita una expresión que contenga D y que siempre sea falsa , para que el compilador la evalúe en dependencia de D
Si solo usa 0, ya no dependerá más y el compilador evaluará como coincide durante el análisis, haciendo que la aserción siempre tenga lugar. Incluso si no será la clase que creará una instancia.