g++ отклоняет мой простой функтор со словами «ожидал тип, получил xyz»
Вопрос
Я играл с функторами в C++.В частности, у меня есть вектор пар, который я хотел бы отсортировать по первому элементу пары.Я начал писать полностью специализированный функтор (т.что-то вроде «bool MyLessThan(MyPair &lhs, MyPair &rhs)»).Затем, просто потому, что такого рода вещи интересны, я хотел попробовать написать общий функтор «Применить F к первым элементам этой пары».Я написал ниже, но g++ это не нравится.Я получил:
ошибка:Тип/значения несоответствия в аргументе 2 в списке параметров шаблона для «ошибки шаблона struct pair1stfunc2»:ожидал типа, получил «меньше»
#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>());
}
Может ли кто-нибудь пролить свет на то, что я здесь делаю неправильно?Я знаю, что это слегка искусственный пример, но мне хотелось бы знать, что происходит, хотя бы для того, чтобы улучшить мой STL-фу.
Решение
Вам необходимо специализировать std::less с типом сравнения, который вы используете.
Pair1stFunc2<MyPair, std::less<int> >()
сделает свое дело.В вашем собственном операторе() вам также потребуется создать экземпляр объекта типа сравнения, поскольку вы не можете просто вызвать класс напрямую.Например.изменять
return F(lhs.first, rhs.first);
к
F func;
return func(lhs.first, rhs.first);
Вы также можете переместить специализацию в функтор, как предполагает другой ответ.
Другие советы
Чтобы раскрыть ответ Диркгентли, вот пример того, что может работать так, как вы собираетесь:
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>());
}
Обратите внимание, что это работает, но это может быть не совсем то, что вы имели в виду.
Обратите внимание, что std :: less
сам по себе является шаблоном, и вы не указываете параметр шаблона шаблона, когда вызываете его с помощью функции foo ()
функции код>! Здесь
less
является неполным типом и, следовательно, проблемой.
Похоже на unwesen. Но вам не нужно использовать шаблоны шаблонов.
#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
}
Самое простое решение - указать в качестве аргумента то, что вы хотите, - функцию с подходящей сигнатурой:
template<typename P, bool (*F)(P,P)> struct Pair1stFunc2 { ... }
В этом случае передача шаблона функции в качестве второго аргумента приведет к разрешению перегрузки с использованием P, P в качестве типов аргумента. Это работает, потому что вы переместите разрешение перегрузки из struct Pair1stFunc2 :: operator ()
Вам также нужна возможность передачи функтора , но они должны быть переданы в качестве аргумента типа шаблона, а затем созданы внутри operator ():
typename F::result_type operator()(const P &lhs, const P &rhs) const
{ return F()(lhs.first, rhs.first); }
Здесь F - это тип функтора, а F () - экземпляр этого функтора.
Третий случай уже описан ранее, шаблон функтора. std :: less - это такой шаблон. В этом случае вам понадобится аргумент шаблона шаблона.