web-dev-qa-db-fra.com

Spécialisation explicite dans la portée non-namespace

template<typename T>
class CConstraint
{
public:
    CConstraint()
    {
    }

    virtual ~CConstraint()
    {
    }

    template <typename TL>
    void Verify(int position, int constraints[])
    {       
    }

    template <>
    void Verify<int>(int, int[])
    {   
    }
};

Compiler ceci sous g ++ donne l'erreur suivante:

Spécialisation explicite dans la 'classe CConstraint' sans la portée de l'espace de noms

En VC, ça compile bien. Quelqu'un peut-il s'il vous plaît laissez-moi savoir la solution de contournement?

120
Mark

Dans ce cas, VC++ n'est pas conforme. Les spécialisations explicites doivent être au niveau de l'espace de noms. C++ 03, §14.7.3/2:

Une spécialisation explicite doit être déclarée dans l'espace de noms dont le modèle est membre ou, pour les modèles de membres, dans l'espace de noms dont la classe ou le modèle de classe est un membre.
Une spécialisation explicite d'une fonction membre, d'une classe membre ou d'un membre de données statiques d'un modèle de classe doit être déclarée dans l'espace de noms dont le modèle de classe est membre.

De plus, vous avez le problème que vous ne pouvez pas spécialiser les fonctions membres sans spécialiser explicitement la classe contenante à cause de C++ 03, §14.7.3/, donc une solution serait de laisser Verify() transmettre à une fonction libre, éventuellement spécialisée:

namespace detail {
    template <typename TL> void Verify     (int, int[]) {}
    template <>            void Verify<int>(int, int[]) {}
}

template<typename T> class CConstraint {
    // ...
    template <typename TL> void Verify(int position, int constraints[]) {
        detail::Verify<TL>(position, constraints);
    }
};
92
Georg Fritzsche

Une autre façon de le résoudre consiste à déléguer à une fonction privée et à surcharger cette fonction. De cette façon, vous avez toujours accès aux données de membre de *this et au type de paramètre du modèle externe.

template<typename T>
struct identity { typedef T type; };

template<typename T>
class CConstraint
{
public:

  template <typename TL>
  void Verify(int position, int constraints[])
  {
    Verify(position, constraints, identity<TL>());
  }

private:
  template<typename TL>
  void Verify(int, int[], identity<TL>)
  {

  }

  void Verify(int, int[], identity<int>)
  {

  }
};
85

Il suffit de prendre la spécialisation de modèle en dehors de la déclaration de classe. gcc n'autorise pas la spécialisation de modèles en ligne.

Une autre option consiste à supprimer simplement le modèle de ligne <>.

12
bop

Mieux encore, vous pouvez combiner une spécialisation partielle avec les arguments de modèle par défaut. De cette façon, les modifications apportées au code VC++ sont mineures, car les appels à la fonction spécialisée n'ont pas besoin d'être modifiés.

template <typename TL, class Dummy=int>
void Verify(int position, int constraints[])
{
}

template <class Dummy=int>
void Verify<int, Dummy>(int, int[])
{
}
4
vitke

Vous ne pourrez peut-être pas spécialiser explicitement le modèle de membre, mais vous pourrez partiellement le spécialiser. Si vous ajoutez un deuxième paramètre "int dummyParam" et que vous l'ajoutez également à la spécialisation, cela devrait fonctionner avec les deux compilateurs.

Non pas que je le sache il y a plus de 10 secondes, mais en recherchant la même erreur sur Google, je me suis heurté à ce lien et cela a fonctionné pour ma spécialisation de modèle de membre.

1
M. Tibbits