使用成员函数作为比较器排序问题

Nav*_*vid 30 c++ sorting stl compiler-errors

试图编译以下代码我得到这个编译错误,我该怎么办?


ISO C++禁止获取非限定或带括号的非静态成员函数的地址,以形成指向成员函数的指针.

class MyClass {
   int * arr;
   // other member variables
   MyClass() { arr = new int[someSize]; }

   doCompare( const int & i1, const int & i2 ) { // use some member variables } 

   doSort() { std::sort(arr,arr+someSize, &doCompare); }

}; 
Run Code Online (Sandbox Code Playgroud)

And*_*nck 28

doCompare一定是static.如果您doCompare需要的数据MyClass可以MyClass通过更改来变成比较仿函数:

doCompare( const int & i1, const int & i2 ) { // use some member variables } 
Run Code Online (Sandbox Code Playgroud)

bool operator () ( const int & i1, const int & i2 ) { // use some member variables } 
Run Code Online (Sandbox Code Playgroud)

并致电:

doSort() { std::sort(arr,arr+someSize, *this); }
Run Code Online (Sandbox Code Playgroud)

还有,是不是doSort错过了返回值?

我认为应该可以使用std::mem_fun和某种绑定将成员函数转换为自由函数,但确切的语法现在避开了我.

编辑: Doh,std::sort按值来获取仿函数,这可能是个问题.为了解决这个问题,请将类中的仿函数包装起来:

class MyClass {
    struct Less {
        Less(const MyClass& c) : myClass(c) {}
        bool operator () ( const int & i1, const int & i2 ) {// use 'myClass'} 
        MyClass& myClass;
    };
    doSort() { std::sort(arr,arr+someSize, Less(*this)); }
}
Run Code Online (Sandbox Code Playgroud)


Kla*_*aim 13

正如Andreas Brinck所说,doCompare必须是静态的(+1).如果你必须在比较器函数中有一个状态(使用该类的其他成员),那么你最好使用函子而不是函数(这会更快):

class MyClass{

   // ...
   struct doCompare
   { 
       doCompare( const MyClass& info ) : m_info(info) { } // only if you really need the object state
       const MyClass& m_info;

       bool operator()( const int & i1, const int & i2  )
       { 
            // comparison code using m_info
       }
   };

    doSort() 
    { std::sort( arr, arr+someSize, doCompare(*this) ); }
};
Run Code Online (Sandbox Code Playgroud)

使用仿函数总是更好,输入时间更长(可能不方便但很好......)

我认为你也可以使用std :: bind和成员函数,但我不知道怎么回事并不容易.

更新2014:今天我们可以访问c ++ 11编译器,因此您可以使用lambda代码,代码会更短但具有完全相同的语义.


aki*_*kim 9

Rob提出的解决方案现在是有效的C++ 11(不需要Boost):

void doSort()
{
  using namespace std::placeholders;
  std::sort(arr, arr+someSize, std::bind(&MyClass::doCompare, this, _1, _2));
}
Run Code Online (Sandbox Code Playgroud)

事实上,正如Klaim所提到的,lambdas是一个选项,有点冗长(你必须"重复"参数是整数):

void doSort()
{
  std::sort(arr, arr+someSize, [this](int l, int r) {return doCompare(l, r); });
}
Run Code Online (Sandbox Code Playgroud)

C++ 14支持auto:

void doSort()
{
  std::sort(arr, arr+someSize, [this](auto l, auto r) {return doCompare(l, r); });
}
Run Code Online (Sandbox Code Playgroud)

但是,你仍然宣称参数是通过副本传递的.

然后问题是"哪一个是最有效的".这个问题由Travis Gockel处理:Lambda vs Bind.他的基准程序在我的计算机上提供(OS X i7)

                        Clang 3.5    GCC 4.9
   lambda                    1001        7000
   bind                3716166405  2530142000
   bound lambda        2438421993  1700834000
   boost bind          2925777511  2529615000
   boost bound lambda  2420710412  1683458000
Run Code Online (Sandbox Code Playgroud)

其中lambda是一个直接使用的lambda,lambda bound是一个存储在一个lambda中的lambda std::function.

所以看起来lambdas是一个更好的选择,这并不是一个惊喜,因为编译器提供了更高级别的信息,从中可以获利.


Rob*_*obᵩ 5

您可以使用boost::bind

void doSort() {
  std::sort(arr,arr+someSize, boost::bind(&MyClass::doCompare, this, _1, _2));
}
Run Code Online (Sandbox Code Playgroud)