c++ - La función de plantilla especializada con el caso "general" eliminado no se compila con g++<= 4.8.0 y clang++
templates c++11 (1)
Compilando un proyecto con una versión anterior de g ++ (4.8.0, MinGW) encontré que este código no se compila:
template<typename T>
void foo() = delete;
template<>
void foo<int>(){}
int main() {
foo<int>();
return 0;
}
Parece que g ++ ni siquiera intenta buscar especializaciones explícitas si ve que se borra el caso base.
mitalia@mitalia:~/scratch$ /opt/mingw32-dw2/bin/i686-w64-mingw32-g++ -std=c++11 buggy_deleted_template.cpp
buggy_deleted_template.cpp: In function ''int main()'':
buggy_deleted_template.cpp:8:14: error: use of deleted function ''void foo() [with T = int]''
foo<int>();
^
buggy_deleted_template.cpp:5:6: error: declared here
void foo<int>(){}
^
mitalia@mitalia:~/scratch$ /opt/mingw32-dw2/bin/i686-w64-mingw32-g++ --version
i686-w64-mingw32-g++ (rubenvb-4.8.0) 4.8.0
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
En cambio, g ++ 4.8.4 y 5.2 (en Linux) no se quejan. ¿Se trata de un error en la versión anterior del compilador o un área gris en el estándar?
Apéndice
clang 3.4.1 también parece que no le gusta:
mitalia@mitalia:~/scratch$ clang++ -std=c++11 buggy_deleted_template.cpp
buggy_deleted_template.cpp:5:6: error: redefinition of ''foo''
void foo<int>(){}
^
buggy_deleted_template.cpp:5:6: note: previous definition is here
buggy_deleted_template.cpp:8:5: error: no matching function for call to ''foo''
foo<int>();
^~~~~~~~
buggy_deleted_template.cpp:2:6: note: candidate template ignored: substitution failure [with T = int]
void foo() = delete;
^
2 errors generated.
mitalia@mitalia:~/scratch$ clang++ --version
Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)
Target: x86_64-pc-linux-gnu
Thread model: posix
(y @Baum mit Augen en los comentarios informa que aún no funciona en 3.7)
No sé si lo siguiente será esclarecedor, pero encontré el informe de defectos 941: Especialización explícita de la plantilla de función eliminada con estado C ++ 11 que dice lo siguiente (énfasis) :
De acuerdo con el párrafo 1 de 14.7.3 [temp.expl.spec], solo las plantillas de funciones no eliminadas pueden estar explícitamente especializadas. Sin embargo, no parece haber una necesidad imperiosa de esta restricción, y podría ser útil prohibir el uso de especializaciones con instancias implícitas mientras se permite el uso de versiones explícitamente especializadas.
Resolución propuesta (febrero, 2010):
Cambie 14.7.3 [temp.expl.spec] párrafo 1 de la siguiente manera:
Una especialización explícita de cualquiera de los siguientes:
no eliminadoplantilla de funciónplantilla de clase
no eliminadoFunción miembro de una plantilla de clase.miembro de datos estáticos de una plantilla de clase
clase miembro de una plantilla de clase
plantilla de clase miembro de una clase o plantilla de clase
no eliminadoplantilla de función miembro de una clase o plantilla de clasepuede ser declarado ...
Ahora el estado actual del borrador del estándar N4527 es 14.7.3 Especialización explícita [temp.expl.spec]:
1 Una especialización explícita de cualquiera de los siguientes:
(1.1) - plantilla de función
(1.2) - plantilla de clase
(1.3) - plantilla variable
(1.4) - Función miembro de una plantilla de clase.
(1.5) - miembro de datos estáticos de una plantilla de clase
(1.6) - clase miembro de una plantilla de clase
(1.7) - enumeración de miembros de una plantilla de clase
(1.8) - plantilla de clase miembro de una clase o plantilla de clase
(1.9) - plantilla de función miembro de una clase o plantilla de clase
...
Así que supongo:
template<typename T>
void foo() = delete;
template<>
void foo<int>(){}
int main() {
foo<int>();
return 0;
}
Es un código compatible con C ++ 11 y debe ser aceptado.