27 votes

Comment puis-je spécialiser une fonction membre de modèle pour std::vector<T> ?

Je dois définir une méthode get de deux manières différentes. Une pour les types simples T. Et une autre pour std::vector.

template<typename T>
const T& Parameters::get(const std::string& key)
{
    Map::iterator i = params_.find(key);
    ...
    return boost::lexical_cast<T>(boost::get<std::string>(i->second));
    ...
}

Comment puis-je spécialiser cette méthode pour std::vector. Comme là, le code devrait ressembler à quelque chose comme ceci :

template<typename T>
const T& Parameters::get(const std::string& key)
{
    Map::iterator i = params_.find(key);
    std::vector<std::string> temp = boost::get<std::vector<std::string> >(i->second)
    std::vector<T> ret(temp.size());
    for(int i=0; i<temp.size(); i++){
         ret[i]=boost::lexical_cast<T>(temp[i]);
    }
    return ret;    
}

Mais je ne sais pas comment spécialiser la fonction pour cela. Merci beaucoup.

31voto

Nawaz Points 148870

Ne pas spécialiser le modèle de fonction.

Utilisez plutôt la surcharge.

Écrire un modèle de fonction get_impl pour traiter le cas général, et surcharge (pas se spécialiser ) pour traiter le cas spécifique, puis appeler get_impl de get comme :

template<typename T>
const T& Parameters::get(const std::string& key)
{
     //read the explanation at the bottom for the second argument!
     return get_impl(key, static_cast<T*>(0) );
}

Et voici les mises en œuvre réelles.

//general case
template<typename T>
const T& Parameters::get_impl(const std::string& key, T*)
{
    Map::iterator i = params_.find(key);
    return boost::lexical_cast<T>(boost::get<std::string>(i->second));
}

//this is overload - not specialization
template<typename T>
const std::vector<T>& Parameters::get_impl(const std::string& key, std::vector<T> *)
{
      //vector specific code
}

El static_cast<T*>(0) en get est juste un moyen délicat de désambiguïser l'appel. Le type de static_cast<T*>(0) es T* et de le passer comme deuxième argument à get_impl aidera le compilateur à choisir la bonne version de get_impl . Si T n'est pas std::vector la première version sera choisie, sinon la deuxième version sera choisie.

3voto

Nim Points 22570

Erm. appelez-le autrement ? par exemple.

template<typename T>
const T& Parameters::getVector(const std::string& key)
{
  Map::iterator i = params_.find(key);
  std::vector<std::string> temp = boost::get<std::vector<std::string> >(i->second)
  // T is already a vector
  T ret; ret.reserve(temp.size());
  for(int i=0; i<temp.size(); i++){
     ret.push_back(boost::lexical_cast<typename T::value_type>(temp[i]));
  }
  return ret;  
}

Vous devrez appeler ça comme :

foo.getVector<std::vector<int> > ("some_key");

Rien dans votre question ne l'exclut.

Maintenant, si vous avez vraiment besoin d'utiliser get() Dans ce cas, vous devez vous contenter de spécialiser partiellement une structure, car la spécialisation partielle des fonctions n'est pas prise en charge par le langage.

C'est beaucoup plus compliqué, par exemple :

template <typename T>
struct getter
{
  const T& operator()(std::string const& key)
  {
    // default operations
  }
};

// Should double check this syntax 
template <typename T>
struct getter<std::vector<T, std::allocator<T> > >
{
  typedef std::vector<T, std::allocator<T> > VecT;
  const VecT& operator()(std::string const& key)
  {
    // operations for vector
  }
};

Alors dans votre méthode devient :

template<typename T>
const T& Parameters::get(const std::string& key)
{
  return getter<T>()(key); // pass the structures getter needs?
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X