web-dev-qa-db-fra.com

spécialisation explicite de la fonction membre de la classe de modèle

J'ai besoin de spécialiser la fonction de membre de modèle pour un certain type (disons double). Cela fonctionne bien alors que la classe X elle-même n'est pas une classe de modèle, mais lorsque je crée ce modèle, 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.

79
ledokol

Ça ne marche pas comme ça. Vous auriez besoin de dire ce qui suit, mais c'est pas correct

template <class C> template<>
void X<C>::get_as<double>()
{

}

De manière explicite membres spécialisés , les modèles de classe qui les entourent doivent également être explicitement spécialisés. Vous devez donc dire ce qui suit, qui ne ferait que spécialiser le membre pour X<int>.

template <> template<>
void X<int>::get_as<double>()
{

}

Si vous souhaitez conserver le modèle environnant non 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>) {

   }
};
95

Si on peut utiliser std::enable_if nous pourrions nous fier à SFINAE (l’échec de la substitution n’est pas une erreur)

cela fonctionnerait comme ceci:

#include <iostream>
#include <type_traits>

template <class C> class X
{
public:
    template <class T, typename std::enable_if< ! std::is_same<double,T>::value>::type * = nullptr > void get_as(){
        std::cout << "get as T" << std::endl;
    }


    template <class T, typename std::enable_if< std::is_same<double,T>::value>::type * = nullptr  > void get_as(){
        std::cout << "get as double" << std::endl;
    }
};


int main()
{

    X<int> d;
    d.get_as<double>();

   return 0;
}

La chose la plus moche est que, avec tous ces éléments, une seule spécialisation doit être disponible pour le compilateur de enable_if, sans quoi une erreur de désambiguïsation se produira. C’est pourquoi le comportement par défaut "get as T" nécessite également une activation de if.

20
Gabriel