Question

J'ai joué avec des foncteurs en C ++. En particulier, j'ai un vecteur de paires que je voudrais trier en fonction du premier élément de la paire. J'ai commencé par écrire un foncteur complètement spécialisé (c'est-à-dire quelque chose comme "bool MyLessThan (MyPair & Lhs, MyPair"). Ensuite, juste parce que ce genre de choses est intéressant, je voulais essayer d’écrire un générique "Appliquer F aux premiers éléments de cette paire". foncteur. J'ai écrit ce qui suit, mais g ++ ne l'aime pas. Je reçois:

erreur: incompatibilité type / valeur à l'argument 2 dans la liste de paramètres de modèle pour 'modèle de structure Pair1stFunc2' error: attendu un type, a obtenu 'moins'

#include <algorithm>
#include <functional>
#include <utility>
#include <vector>

template <class P, class F>
struct Pair1stFunc2
{
    typename F::result_type operator()(P &lhs, P &rhs) const
    { return F(lhs.first, rhs.first); }

    typename F::result_type operator()(const P &lhs, const P &rhs) const
    { return F(lhs.first, rhs.first); }
};

typedef std::pair<int,int> MyPair;
typedef std::vector<MyPair> MyPairList;

MyPairList pairs;

void foo(void)
{
    std::sort(pairs.begin(),
              pairs.end(),
              Pair1stFunc2<MyPair, std::less>());
}

Quelqu'un peut-il nous éclairer sur ce que je fais de mal ici? Je sais que cet exemple est légèrement artificiel, mais j'aimerais savoir ce qui se passe, ne serait-ce que pour améliorer mon STL-fu.

Était-ce utile?

La solution

Vous devez spécialiser std :: less avec le type de comparaison que vous utilisez.

Pair1stFunc2<MyPair, std::less<int> >()

fera l'affaire. Dans votre propre opérateur (), vous devrez également instancier un objet du type comparaison, car vous ne pouvez pas simplement appeler la classe directement. Par exemple. changer

return F(lhs.first, rhs.first);

à

F func;
return func(lhs.first, rhs.first);

Vous pouvez également déplacer la spécialisation dans le foncteur, comme le suggère une autre réponse.

Autres conseils

Pour développer la réponse de dirkgently, voici un exemple de ce qui pourrait fonctionner comme vous le souhaitez:

template <typename T, template <typename> class F>
struct Pair1stFunc2
{
    template <typename P>
    typename F<T>::result_type operator()(P &lhs, P &rhs) const
    { F<T> f; return f(lhs.first, rhs.first); }

    template <typename P>
    typename F<T>::result_type operator()(const P &lhs, const P &rhs) const
    { F<T> f; return f(lhs.first, rhs.first); }
};

void foo(void)
{
    std::sort(pairs.begin(),
              pairs.end(),
              Pair1stFunc2<int, std::less>());
}

Notez que cela fonctionne, mais ce n'est peut-être pas exactement ce que vous aviez à l'esprit.

Notez que std :: less est lui-même un modèle et que vous ne spécifiez pas le paramètre de modèle de modèle lorsque vous l'appelez avec foo () dans le tri de la fonction ! Ici moins est un type incomplet et donc le problème.

Similaire à Inattendu. Mais vous n'avez pas besoin d'utiliser des modèles de modèles.

#include <algorithm>
#include <functional>
#include <memory>
#include <vector>

typedef std::pair<int,int> MyPair;
typedef std::vector<MyPair> MyPairList;
MyPairList pairs;


// Same as original.
template <typename T,typename F>
struct Pair1stFunc2
{
    template <typename P>
    typename F::result_type operator()(P &lhs, P &rhs) const
    { F f;  // Just need to create an anstance of the functor to use.
      return f(lhs.first, rhs.first); }

    template <typename P>
    typename F::result_type operator()(const P &lhs, const P &rhs) const
    { F f;  // Just need to create an anstance of the functor to use.
      return f(lhs.first, rhs.first); }
};


void foo(void)
{
    std::sort(pairs.begin(),
              pairs.end(),
              Pair1stFunc2<int, std::less<int> >()); // initialize the version of less
}

La solution la plus simple serait d’énoncer ce que vous voulez en tant qu’argument, une fonction avec une signature appropriée:

template<typename P, bool (*F)(P,P)> struct Pair1stFunc2 { ... }

Dans ce cas, le fait de passer un modèle de fonction en tant que deuxième argument entraînera la résolution de la surcharge avec P, P en tant que types d'arguments. Cela fonctionne car vous déplacez la résolution de surcharge de struct Pair1stFunc2 :: operator ()

Vous souhaitez également pouvoir transmettre un foncteur , mais ceux-ci doivent être transmis en tant qu'argument de type modèle, puis créés à l'intérieur de operator ():

typename F::result_type operator()(const P &lhs, const P &rhs) const
{ return F()(lhs.first, rhs.first); }

Ici, F est le type de foncteur et F () une instance de ce foncteur.

Le troisième cas est déjà couvert précédemment, le modèle de foncteur. std :: less est un tel modèle. Dans ce cas, vous avez besoin d’un argument de modèle.

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