6

我一直在玩 C++ 中的函子。特别是,我有一个对的向量,我想按对的第一个元素进行排序。我开始编写一个完全专业的仿函数(例如“bool MyLessThan(MyPair &lhs, MyPair &rhs)”)。然后,仅仅因为这类东西很有趣,我想尝试编写一个通用的“将 F 应用于这对的第一个元素”函子。我在下面写了,但 g++ 不喜欢它。我得到:

错误:“模板结构 Pair1stFunc2”的模板参数列表中参数 2 的类型/值不匹配错误:预期类型,得到“更少”

#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-fu。

4

5 回答 5

6

为了扩展 dirkgently 的答案,这里有一个示例,说明可能会按您的意图工作:

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

请注意,它有效,但可能与您的想法不完全一致。

于 2009-05-05T14:22:30.550 回答
3

请注意,它本身就是一个模板,当您使用函数的!std::less调用它时,您没有指定模板模板参数。这是一个不完整的类型,因此是问题所在。foo()sortless

于 2009-05-05T14:13:17.920 回答
2

您需要使用您正在使用的比较类型专门化 std::less 。

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

会成功的。在您自己的 operator() 中,您还需要实例化一个比较类型的对象,因为您不能直接调用该类。例如改变

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

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

正如另一个答案所暗示的那样,您还可以将专业化移动到函子中。

于 2009-05-05T14:19:28.703 回答
2

类似于 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
}
于 2009-05-05T15:13:35.857 回答
1

最简单的解决方案是将您想要的参数声明为具有合适签名的函数:

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

在这种情况下,将函数模板作为第二个参数传递将导致以 P,P 作为参数类型对其进行重载解析。这是有效的,因为您将重载解决方案移出struct Pair1stFunc2::operator()

您还希望可以传入functor,但这些确实需要作为模板类型参数传递,然后在 operator() 内部创建:

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

这里,F 是函子类型,F() 是函子的一个实例。

第三种情况已经在前面介绍过,即仿函数模板。std::less 就是这样一个模板。在这种情况下,您需要一个模板模板参数。

于 2009-05-05T14:40:56.263 回答