c++ - installed - Plantilla de especialización parcial para parámetros no tipográficos integrales y no tipográficos no integrales, diferencia entre g++ y clang
llvm 3.7 0 (2)
Creo que en clang nullptr
es más como una variable in-build como el tipo int
-build int
. nullptr
realidad no tiene ningún tipo. La declaración (no hay definición) de nullptr_t
es struct nullptr_t nullptr_t;
. Y la respuesta para la pregunta uno que es correcta ... la respuesta es que ambas tienen razón porque existe una norma, pero estos son compiladores diferentes hechos de diferentes compañías, por lo que puede haber diferencias entre GNU G++
y Clang
. Se suponía que Clang
era totalmente compatible con G++
pero no lo es.
La siguiente es una plantilla simple de especialización parcial:
// #1
template <typename T, T n1, T n2>
struct foo {
static const char* scenario() {
return "#1 the base template";
}
};
// #2
// partial specialization where T is unknown and n1 == n2
template <typename T, T a>
struct foo<T, a, a> {
static const char* scenario() {
return "#2 partial specialization";
}
};
El principal a continuación obtiene diferentes resultados en g ++ (6.1) y clang ++ (3.8.0):
extern const char HELLO[] = "hello";
double d = 2.3;
int main() {
cout << foo<int, 1, 2> ::scenario() << endl;
cout << foo<int, 2, 2> ::scenario() << endl;
cout << foo<long, 3, 3> ::scenario() << endl;
cout << foo<double&, d, d> ::scenario() << endl;
cout << foo<double*, &d, &d> ::scenario() << endl;
cout << foo<double*, nullptr, nullptr> ::scenario() << endl;
cout << foo<int*, nullptr, nullptr> ::scenario() << endl;
cout << foo<nullptr_t, nullptr, nullptr> ::scenario() << endl;
cout << foo<const char*, HELLO, HELLO> ::scenario() << endl;
}
resultados en g ++ y clang
# | The code | g++ (6.1) | clang++ (3.8.0) |
1 | foo<int, 1, 2> | #1 as expected | #1 as expected |
2 | foo<int, 2, 2> | #2 as expected | #2 as expected |
3 | foo<long, 3, 3> | #2 as expected | #2 as expected |
4 | foo<double&, d, d> | #1 -- why? | #2 as expected |
5 | foo<double*, &d, &d> | #2 as expected | #2 as expected |
6 | foo<double*, nullptr, nullptr> | #2 as expected | #1 -- why? |
7 | foo<int*, nullptr, nullptr> | #2 as expected | #1 -- why? |
8 | foo<nullptr_t, nullptr, nullptr> | #2 as expected | #1 -- why? |
9 | foo<const char*, HELLO, HELLO> | #2 as expected | #2 as expected |
¿Cuál es la correcta?
Código: http://coliru.stacked-crooked.com/a/45ba16c9f021fd84
El # 4 está mal formado, me sorprende que compile. Por un lado, un doble no se puede usar como un parámetro de plantilla no tipo. Por otra parte, una plantilla de clase usa las mismas reglas que las plantillas de función para el ordenamiento parcial. El estándar proporciona un ejemplo de las funciones "imaginarias" generadas para realizar el pedido:
template<int I, int J, class T> class X { };
template<int I, int J> class X<I, J, int> { }; // #1
template<int I> class X<I, I, int> { }; // #2
template<int I, int J> void f(X<I, J, int>); // A
template<int I> void f(X<I, I, int>); // B
Para su ejemplo, se vería algo como esto:
template <typename T, T n1, T n2>
struct foo {
};
template <typename T, T n1, T n2>
void bar(foo<T, n1, n2>)
{
std::cout << "a";
}
template <typename T, T a>
void bar(foo<T, a, a>)
{
std::cout << "b";
}
La deducción de argumentos de plantilla se utiliza para determinar qué función es más especializada que la otra. Un double&
debería deducirse como un double
y, por lo tanto, ambas especializaciones deberían ser iguales, también conocidas como ambiguas para la bar(foo<double&, d, d>{});
. He aquí que se quejan GCC y Clang:
Error GCC
main.cpp: 14: 6: nota: la deducción / sustitución del argumento de la plantilla falló: main.cpp: 26: 29: nota: tipos no coincidentes ''double &'' y ''double''
bar(foo<double&, d, d>{}); ^
Error de sonido
nota: la plantilla candidata se ignora: falla de sustitución [con T = doble &]: el argumento de la plantilla deducida que no es del tipo no tiene el mismo tipo que el parámetro de su plantilla correspondiente (''doble'' vs ''doble &'')
Y nuevamente, si elimina la referencia, ambos se quejan correctamente de usar el double
como un parámetro de plantilla no tipo.
No voy a probar el resto, pero puede encontrar resultados similares.