Question

Compte tenu des modèles de fonction suivante:

#include <vector>
#include <utility>

struct Base { };
struct Derived : Base { };

// #1
template <typename T1, typename T2>
void f(const T1& a, const T2& b)
{
};

// #2
template <typename T1, typename T2>
void f(const std::vector<std::pair<T1, T2> >& v, Base* p)
{
};

Pourquoi est-ce que le code suivant appelle toujours la surcharge # 1 au lieu de surcharge # 2?

int main()
{
    std::vector<std::pair<int, int> > v;
    Derived derived;

    f(100, 200);  // clearly calls overload #1
    f(v, &derived);         // always calls overload #1

    return 0;
}

Étant donné que le deuxième paramètre de f est un type dérivé de Base, j'espérais que le compilateur choisirait la surcharge # 2 car il est une meilleure correspondance que le type générique en surcharge # 1.

Y a-t-il des techniques que je pourrais utiliser pour réécrire ces fonctions afin que l'utilisateur peut écrire du code tel qu'il est affiché dans la fonction main (à savoir, tirant parti de compilateur déduction des types d'arguments)?

Était-ce utile?

La solution

Vous pouvez faire ceci:

f(v, static_cast<Base*>(&derived));

Ou utilisez SFINAE pour enlever la première fonction en tant que candidat de sélection:

// Install boost library and add these headers:
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>

// #1 - change it to look like this (note the keyword void changed positions)
template <typename T1, typename T2>
typename boost::disable_if<
   typename boost::is_convertible<T2, Base*>, void>::type
f(const T1& a, const T2& b)
{
};

// #2 - this one can stay the same
template <typename T1, typename T2>
void f(const std::vector<std::pair<T1, T2> >& v, Base* p)
{
};

Autres conseils

  

Etant donné que le second paramètre de f est un type dérivé de la base

Il est convertible à un tel, mais il est un Derived *. La première fonction de modèle nécessite aucune conversion, et le second a besoin d'un, donc il choisit la première.

choisit la seconde:

f(v, static_cast<Base*>(&derived));

Sur une note de côté, main retourne un int.

En plus des sujets évidents sur Koenig Recherche qui est plus ou moins bien mis en œuvre par les compilateurs ( en particulier les plus âgés sont tout à fait problématique), il y a quelques pièges concernant .

La spécialisation requiert des types pour correspondre exactement (ne sais pas comment l'std définit, mais de mon expérience [gcc, msvc] ne sera pas égalé une classe dérivée). Si vous ajoutez un casting laid à la base *, il devrait fonctionner comme vous avez l'intention, le cas échéant ajouter une autre spécialisation dérivé ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top