g++ отклоняет мой простой функтор со словами «ожидал тип, получил xyz»

StackOverflow https://stackoverflow.com/questions/825015

  •  05-07-2019
  •  | 
  •  

Вопрос

Я играл с функторами в 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 - это такой шаблон. В этом случае вам понадобится аргумент шаблона шаблона.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top