Tratando de especializarse en función de la validez del tamaño de la matriz:
// base template
template<int p, typename T = void>
struct absolute {
operator int () const { return 0; }
};
// positive case template
template<int p>
struct absolute<p, typename std::void_t<int[p]>> {
operator int () const { return p; }
};
// negative case template
template<int p>
struct absolute<p, typename std::void_t<int[-p]>> {
operator int () const { return -p; }
};
int main() {
std::cout << absolute<5>() << std::endl;
std::cout << absolute<-5>() << std::endl;
std::cout << absolute<0>() << std::endl;
}
Problema 1:
El código anterior funciona bien con gcc pero no puede compilarse con clang .
Clang genera el error: redefinición de la estructura de la plantilla 'absoluta'
¿Quién tiene la razón?
Problema # 2:
Tanto con gcc como con clang (si eliminamos la especialización negativa para devolver el clang al juego), no está claro por qué absolute<0>()
selecciona la plantilla base. No hay nada de malo en int[0]
lo std::void_t<int[0]>
que parece ser más especializado:
// base template
template<int p, typename T = void>
struct absolute {
operator int () const { return -1; }
};
// positive case template
template<int p>
struct absolute<p, typename std::void_t<int[p]>> {
operator int () const { return p; }
};
int main() {
std::cout << absolute<5>() << std::endl; // 5
std::cout << absolute<0>() << std::endl; // -1, why not 0?
}
Y ... si la plantilla base se declara sin implementación, como:
// base template
template<int p, typename T = void>
struct absolute;
Tanto gcc y sonido metálico dejarían de compilación , se quejan en el uso inválido de tipo incompleto para la llamada: absolute<0>()
. A pesar de que parece encajar en el caso especializado.
¿Porqué es eso?
int[0]
está prohibido por el estándar ISO C ++ timsong-cpp.github.io/cppwp/n4659/dcl.array#1 "su valor será mayor que cero"
template<int p> struct absolute<p, typename std::void_t<int[p]>>
ytemplate<int p> struct absolute
no es eso un duplicado?