Pergunta

Eu tenho jogado sobre com functors em C ++. Em particular, eu tenho um vetor de pares Eu gostaria de classificar pelo primeiro elemento do par. Comecei escrevendo um functor completamente especializada (algo ou seja, como "bool MyLessThan (MyPair & lhs, MyPair & RHS)"). Então, só porque esse tipo de coisa é interessante, eu queria tentar escrever um genérico "Aplicar F para os primeiros elementos deste par" functor. Eu escrevi o abaixo, mas g ++ não gosta. Eu recebo:

erro: Tipo / valor incompatibilidade no argumento 2 na lista de parâmetros de modelo para 'template struct Pair1stFunc2' erro: esperava um tipo, tem 'menos'

#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>());
}

Alguém pode lançar alguma luz sobre o que estou fazendo de errado aqui? Eu sei que isto é como exemplo um pouco artificial, mas eu gostaria de saber o que está acontecendo, mesmo que apenas para melhorar a minha STL-fu.

Foi útil?

Solução

Você precisa se especializar std :: menos com o tipo de comparação que você está usando.

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

irá fazer o truque. Dentro do seu próprio operador () você também vai precisar instanciar um objeto do tipo de comparação, já que você não pode simplesmente chamar a classe diretamente. Por exemplo. mudança

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

para

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

Você também pode mover a especialização para o functor, como outra resposta sugere.

Outras dicas

Para expandir a resposta de dirkgently, aqui está um exemplo do que pode funcionar como você pretende:

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>());
}

Note que ele funciona, mas pode não ser exatamente o que você tinha em mente.

Note que std::less é em si um modelo e você não especificar o parâmetro do modelo modelo quando você chamá-lo de com foo() da função sort! Aqui less é um tipo incompleto e, portanto, o problema.

Semelhante ao unwesen. Mas você não precisa de molde moldes uso.

#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
}

A solução mais simples seria a de estado o que você quer como um argumento, uma função com uma assinatura apropriada:

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

Neste caso, a passagem de um modelo de função como segundo argumento fará com resolução de sobrecarga a ser feito sobre ele com P, P, como os tipos de argumento. Isso funciona porque você mover a resolução de sobrecarga de struct Pair1stFunc2::operator()

Você também quer a possibilidade de passar em um functor , mas aqueles precisa ser passado como um argumento tipo de modelo e, em seguida, criado dentro do operador ():

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

Aqui, F é o tipo functor e F () uma instância de que functor.

O terceiro caso é já abordado anteriormente, o modelo functor. std :: menos é um tal modelo. Nesse caso, você precisa de um argumento modelo modelo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top