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

时间:2009-12-14 17:31:36

标签: 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); }

}; 

8 个答案:

答案 0 :(得分:28)

doCompare必须为static。如果doCompare需要来自MyClass的数据,您可以通过更改以下内容将MyClass变为比较仿函数:

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

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

并致电:

doSort() { std::sort(arr,arr+someSize, *this); }

此外,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)); }
}

答案 1 :(得分: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) ); }
};

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

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

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

答案 2 :(得分:8)

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

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

事实上,正如Klaim所说,lambdas是一个选项,更加冗长(你必须重复#34;参数是整数):

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

C ++ 14支持auto

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

但是,你仍然声明参数是通过副本传递的。

然后问题是"哪一个是最有效的"。特拉维斯·戈克尔对此问题进行了处理: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

其中lambda是直接使用的lambda,而lambda bound是存储在std::function中的lambda。

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

答案 3 :(得分:4)

您可以使用boost::bind

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

答案 4 :(得分:2)

有一种方法可以做你想要的,但你需要使用一个小适配器。由于STL不为您编写,可以自己编写:

template <class Base, class T>
struct adaptor_t
{
  typedef bool (Base::*method_t)(const T& t1, const T& t2));
  adaptor_t(Base* b, method_t m)
    : base(b), method(m)
  {}
  adaptor_t(const adaptor_t& copy) : base(copy.base), method(copy.method) {}
  bool operator()(const T& t1, const T& t2) const {
    return (base->*method)(t1, t2);
  }
  Base *base;
  method_t method;
}
template <class Base, class T>
adaptor_t<Base,T> adapt_method(Base* b, typename adaptor_t<Base,T>::method_t m)
{  return adaptor_t<Base,T>(b,m); }

然后,您可以使用它:

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

答案 5 :(得分:0)

有效使用成员函数的一种非常简单的方法是使用运算符&lt;。也就是说,如果你有一个名为compare的函数,你可以从运算符&lt;中调用它。这是一个有效的例子:

class Qaz
{
public:
Qaz(int aX): x(aX) { }

bool operator<(const Qaz& aOther) const
    {
    return compare(*this,aOther);
    }

static bool compare(const Qaz& aP,const Qaz& aQ)
    {
    return aP.x < aQ.x;
    }

int x;
};

然后你甚至不需要将函数名称赋给std :: sort:

std::vector<Qaz> q;
q.emplace_back(8);
q.emplace_back(1);
q.emplace_back(4);
q.emplace_back(7);
q.emplace_back(6);
q.emplace_back(0);
q.emplace_back(3);
std::sort(q.begin(),q.end());

答案 6 :(得分:0)

更新Graham Asher答案,因为您不需要比较,但可以直接使用less运算符。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class Qaz {
public:
    Qaz(int aX): x(aX) { }

    bool operator<(const Qaz& aOther) const {
       return x < aOther.x;
    }

int x;
};

int main() {
    std::vector<Qaz> q;
    q.emplace_back(8);
    q.emplace_back(1);
    q.emplace_back(4);
    q.emplace_back(7);
    q.emplace_back(6);
    q.emplace_back(0);
    q.emplace_back(3);
    std::sort(q.begin(),q.end());
    for (auto& num : q)
        std::cout << num.x << "\n";

    char c;
    std::cin >> c;
    return 0;
}

答案 7 :(得分:0)

std::sort()调用中的第三个参数与std::sort()所需的函数指针不兼容。有关成员函数签名为何与常规函数签名不同的详细说明,请参见my answer to another question