g ++ отклоняет мой простой функтор с «ожидал тип, получил« xyz »» - PullRequest
5 голосов
/ 05 мая 2009

Я играл с функторами в C ++. В частности, у меня есть вектор пар, который я хотел бы отсортировать по первому элементу пары. Я начал с написания полностью специализированного функтора (то есть что-то вроде "bool MyLessThan (MyPair & lhs, MyPair & rhs)"). Затем, просто потому, что такие вещи интересны, я хотел попробовать написать общий функтор «Применить F к первым элементам этой пары». Я написал ниже, но g ++ это не нравится. Я получаю:

ошибка: несоответствие типа / значения в аргументе 2 в списке параметров шаблона для 'template 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-фу.

Ответы [ 5 ]

6 голосов
/ 05 мая 2009

Чтобы развернуть ответ Диркгентли, вот пример того, что может работать так, как вы намереваетесь:

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

Обратите внимание, что это работает, но это может быть не совсем то, что вы имели в виду.

3 голосов
/ 05 мая 2009

Обратите внимание, что std::less сам по себе является шаблоном, и вы не указываете параметр шаблона шаблона, когда вызываете его с помощью foo() функции sort! Здесь less является неполным типом и, следовательно, проблема.

2 голосов
/ 05 мая 2009

Похоже на 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
}
2 голосов
/ 05 мая 2009

Вам нужно специализировать std :: less с типом сравнения, который вы используете.

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

сделает свое дело. В вашем собственном операторе () вам также нужно создать экземпляр объекта типа сравнения, поскольку вы не можете просто вызвать класс напрямую. Например. изменить

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

до

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

Вы также можете перенести специализацию в функтор, как предлагает другой ответ.

1 голос
/ 05 мая 2009

Самое простое решение - указать в качестве аргумента то, что вы хотите, - функцию с подходящей сигнатурой:

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

...