g ++ rejeita minha simples functor com “esperou um tipo, tem 'xyz'”
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.
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.