【问题标题】:compile error when making functor a class member function使函子成为类成员函数时出现编译错误
【发布时间】:2011-02-19 18:01:27
【问题描述】:

我有一个函子,我想将它与 sort() 一起使用,有问题的容器具有类型

std::list<std::pair<unsigned, unsigned>>

此容器是在 GameBoard 类的函数之一中临时初始化的。

函子有声明

bool GameBoard::SortMoveList(std::pair<unsigned, unsigned> left, 
                             std::pair<unsigned, unsigned> right)

使用仿函数时出现编译错误,如下所示:

moveList.sort(&GameBoard::SortMoveList);

错误:

1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\list(1324): error C2064: term does not evaluate to a function taking 2 arguments
1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\list(1394) : see reference to function template instantiation 'void std::list<_Ty>::merge<_Pr3>(std::list<_Ty> &,_Pr3)' being compiled
1>          with
1>          [
1>              _Ty=std::pair<unsigned int,unsigned int>,
1>              _Pr3=bool (__thiscall GameBoard::* )(std::pair<unsigned int,unsigned int>,std::pair<unsigned int,unsigned int>)
1>          ]
1>          GameBoard.cpp(341) : see reference to function template instantiation 'void std::list<_Ty>::sort<bool(__thiscall GameBoard::* )(std::pair<_Ty1,_Ty2>,std::pair<_Ty1,_Ty2>)>(_Pr3)' being compiled
1>          with
1>          [
1>              _Ty=std::pair<unsigned int,unsigned int>,
1>              _Ty1=unsigned int,
1>              _Ty2=unsigned int,
1>              _Pr3=bool (__thiscall GameBoard::* )(std::pair<unsigned int,unsigned int>,std::pair<unsigned int,unsigned int>)
1>          ]

知道这里出了什么问题吗? 仿函数需要访问类的私有数据,所以我将它设为成员 fn。如果它不是成员 fn,它编译得很好。我该如何解决这个问题?

谢谢

【问题讨论】:

  • 注意,这不是函子,这只是一个函数!
  • 你尝试使用排序功能的代码是什么?
  • @Tim 代码是 moveList.sort(&GameBoard::SortMoveList);它列在错误上方的问题中。
  • 仿函数是一个,而不是一个函数。您可以将其设为嵌套类和/或朋友。
  • 这是 CS280 作业吗?如果是,则需要标记为作业

标签: c++ visual-studio-2010 stl functor


【解决方案1】:

仿函数是一个行为类似于函数的对象

这意味着你需要定义一个定义operator()的类

例子:

class GameBoardMoveListSorter
{
    bool operator()(std::pair<unsigned, unsigned> const& left, 
                    std::pair<unsigned, unsigned> const& right) const
    {
        return left.first < right.first; // or whatever your strict weak ordering is.
    }
};

/// STUFF

moveList.sort(GameBoardMoveListSorter());

根据评论编辑:

其他人的意见请:

尽管新标准允许内部类访问封闭类的私有成员。但是刚刚重新阅读了似乎不是我所看到的措辞的标准(编译器的行为似乎允许访问(尽管我知道这方面的一致性一直很弱))。

第 9.7 节第 4 段

与成员函数一样,嵌套类中定义的友元函数 (11.4) 也在该类的词法范围内;它遵守与该类 (9.4) 的静态成员函数相同的名称绑定规则,但它对封闭类的成员没有特殊的访问权限

基于手册的上述部分。内部类必须是友元类才能访问外部类的私有成员。

注意。与 java 不同,内部类和外部类之间没有隐含的父关系。因此,内部类必须具有对外部类对象的显式引用才能访问其成员。

#include <memory>

class Chess
{
    private:
        int     board[8][8];


        class GameBoardMoveListSorter
        {
            GameBoardMoveListSorter(Chess& p)
                : parent(p)
            {}

            bool operator()(std::pair<unsigned, unsigned> const& left,
                            std::pair<unsigned, unsigned> const& right) const
            {
                int val = parent.board[0][0] + parent.board[7][7];
                return left.first + val < right.first - val; // or whatever your strict weak ordering is.
            }

            Chess&      parent;
        };
        // I believe that it must be a friend to access private members.
        friend class GameBoardMoveListSorter;

    public:
        void makeMove()
        {
             std::list<std::pair<unsigned, unsigned> >  moveList(/*Generate Moves*/);

             moveList.sort(GameBoardMoveListSorter(*this));
             // Do something with the move list.
        }
};

【讨论】:

  • @Martin 问题是如果我需要访问 GameBoard 类的私有方法和数据,我应该在哪里定义这个类?
  • @Martin,感谢您的额外解释。最后一个问题:如果我们维护一个指向 Chess 类的指针,使用朋友类会更好吗?为什么/为什么不?
  • @aCuria:还有一个更新。它需要成为朋友(见更新)。
  • @Martin 1) 如果我们让函子成为朋友,是否有理由在国际象棋类中定义 GameBoardMoveListSorter 类? 2) 让重载的 operator()() 成为国际象棋的朋友就足够了吗?很抱歉有多个问题,我的参考书并没有真正详细讨论这个问题。
  • 我测试过让 operator()() 成为朋友。它编译并运行良好。
【解决方案2】:

您不能以这种方式使用成员函数,因为 sort() 没有需要调用它的对象的概念。正如您在 MSVC10 中一样,最简单的解决方案是 lambda。

std::sort(..., [&, this] -> bool (std::pair<unsigned, unsigned> left, std::pair<unsigned, unsigned> right) {
        return this->SortMoveList(left, right);
});

【讨论】:

  • 您能详细说明一下吗?我以前从未使用过 lambda 函数,它们可以在 gcc/borland 中工作吗?顺便说一句,当我用上面的代码替换对 sort() 的调用时,Visual Studio 抱怨语法......
  • 我发现了问题,贴出来的语法有点不对。正确的语法是:moveList.sort( [&, this] (std::pair left, std::pair right) -> bool { return this->SortMoveList(left, right) ; });
  • @aCuria:如果你有最新版本,它们可能在 GCC 中工作,Borland 不太可能有足够新的版本。是的,我发布了一些用于调用 std::sort 的快速伪代码,我不知道您的 moveList 类型是什么或成员函数需要什么。
  • 我知道它的快速伪代码。我刚刚为将来发现此问题的任何人发布了正确的语法=)+1
【解决方案3】:

您可以将该函数与 boost::bind 一起使用。

moveList.sort(boost::bind(&GameBoard::SortMoveList, this, _1, _2 ) );

如果您的实现不需要“this”那么(即它不咨询任何类成员来进行比较),那么不要将其设为类成员函数(甚至不是静态函数)。

注意:对于boost::bind,您可以替换为std::bindstd::tr1::bind,这取决于VC10 附带的应该可以工作的内容。

【讨论】:

  • 它需要调用类方法并访问类数据才能工作。
  • 那么这个解决方案应该可以工作。 VC10 带有 std::bind 或 std::tr1::bind ,您可以在此处使用它们来代替 boost::bind。
猜你喜欢
  • 1970-01-01
  • 2019-02-17
  • 1970-01-01
  • 2019-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多