Necesito especializar la función de miembro de plantilla para algún tipo (digamos doble ). Funciona bien, mientras que la clase en X
sí no es una clase de plantilla, pero cuando la hago, la plantilla GCC comienza a dar errores en tiempo de compilación.
#include <iostream>
#include <cmath>
template <class C> class X
{
public:
template <class T> void get_as();
};
template <class C>
void X<C>::get_as<double>()
{
}
int main()
{
X<int> x;
x.get_as();
}
Aquí está el mensaje de error
source.cpp:11:27: error: template-id
'get_as<double>' in declaration of primary template
source.cpp:11:6: error: prototype for
'void X<C>::get_as()' does not match any in class 'X<C>'
source.cpp:7:35: error: candidate is:
template<class C> template<class T> void X::get_as()
¿Cómo puedo solucionarlo y cuál es el problema aquí?
Gracias por adelantado.
c++
templates
gcc
specialization
ledokol
fuente
fuente
Respuestas:
No funciona de esa manera. Usted tendría que decir lo siguiente, pero es no correcta
template <class C> template<> void X<C>::get_as<double>() { }
Los miembros explícitamente especializados necesitan que sus plantillas de clases circundantes también estén explícitamente especializadas. Por lo tanto, debe decir lo siguiente, que solo especializaría al miembro
X<int>
.template <> template<> void X<int>::get_as<double>() { }
Si desea mantener la plantilla circundante sin especializar, tiene varias opciones. Prefiero las sobrecargas
template <class C> class X { template<typename T> struct type { }; public: template <class T> void get_as() { get_as(type<T>()); } private: template<typename T> void get_as(type<T>) { } void get_as(type<double>) { } };
fuente
type<>
envoltura? ¿No podríaT
hacer el truco una conversión de un 0 a un puntero de tipo ? Supongo que no es tan elegante ...template<typename T> void get_as(T*); void get_as(double*);
y pasar un(T*)0
.Si uno puede usar
std::enable_if
, podríamos confiar en SFINAE (la falla de sustitución no es un error)que funcionaría así (ver EN VIVO ):
#include <iostream> #include <type_traits> template <typename C> class X { public: template <typename T, std::enable_if_t<!std::is_same_v<double,T>, int> = 0> void get_as() { std::cout << "get as T" << std::endl; } template <typename T, std::enable_if_t<std::is_same_v<double,T>, int> = 0> void get_as() { std::cout << "get as double" << std::endl; } }; int main() { X<int> d; d.get_as<double>(); return 0; }
Lo feo es que, con todos estos enable_if, solo una especialización necesita estar disponible para el compilador, de lo contrario surgirá un error de desambiguación. Es por eso que el comportamiento predeterminado "obtener como T" también necesita habilitar si.
fuente