J'ai besoin de spécialiser la fonction membre de modèle pour un type (disons double ). Cela fonctionne bien alors que la classe X
elle-même n'est pas une classe de modèle, mais quand je la crée, GCC commence à donner des erreurs de compilation.
#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();
}
Voici le message d'erreur
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()
Comment puis-je résoudre ce problème et quel est le problème ici?
Merci d'avance.
c++
templates
gcc
specialization
ledokol
la source
la source
Réponses:
Cela ne fonctionne pas de cette façon. Vous auriez besoin de dire ce qui suit, mais ce n'est pas correct
template <class C> template<> void X<C>::get_as<double>() { }
Les membres explicitement spécialisés ont besoin que leurs modèles de classe environnants soient également explicitement spécialisés. Vous devez donc dire ce qui suit, ce qui ne spécialiserait le membre que pour
X<int>
.template <> template<> void X<int>::get_as<double>() { }
Si vous souhaitez que le modèle environnant ne soit pas spécialisé, vous avez plusieurs choix. Je préfère les surcharges
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>) { } };
la source
type<>
emballage? un cast d'un 0 vers un pointeur de typeT
ne pourrait-il pas faire l'affaire? Je suppose que ce n'est pas aussi élégant ...template<typename T> void get_as(T*); void get_as(double*);
et de passer un(T*)0
.Si on est capable de l'utiliser,
std::enable_if
on pourrait compter sur SFINAE (l'échec de la substitution n'est pas une erreur)cela fonctionnerait comme ça (voir EN DIRECT ):
#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; }
La chose laide est que, avec tous ces enable_if, une seule spécialisation doit être disponible pour le compilateur, sinon une erreur d'homonymie se produira. C'est pourquoi le comportement par défaut "get as T" a également besoin d'un enable if.
la source