C++ 使用成员函数作为比较器进行排序的问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1902311/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:32:04  来源:igfitidea点击:

problem sorting using member function as comparator

c++sortingstlcompiler-errors

提问by Navid

trying to compile the following code I get this compile error, what can I do?

尝试编译以下代码时出现此编译错误,我该怎么办?



ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.

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

}; 

回答by Andreas Brinck

doComparemust be static. If doCompareneeds data from MyClassyou could turn MyClassinto a comparision functor by changing:

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

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

into

进入

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

and calling:

并调用:

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

Also, isn't doSortmissing a return value?

另外,是不是doSort缺少返回值?

I think it should be possible to use std::mem_funand some sort of binding to turn the member function into a free function, but the exact syntax evades me at the moment.

我认为应该可以使用std::mem_fun某种绑定将成员函数转换为自由函数,但目前我无法理解确切的语法。

EDIT:Doh, std::sorttakes the functor by value which may be a problem. To get around this wrap the functor inside the class:

编辑: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)); }
}

回答by Klaim

As Andreas Brinck says, doCompare must be static (+1). If you HAVE TO have a state in your comparator function (using the other members of the class) then you'd better use a functor instead of a function (and that will be faster):

正如 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) ); }
};

Using a functor is always better, just longer to type (that can be unconvenient but oh well...)

使用函子总是更好,只是打字时间更长(这可能不方便,但哦……)

I think you can also use std::bind with the member function but I'm not sure how and that wouldn't be easy to read anyway.

我认为您也可以将 std::bind 与成员函数一起使用,但我不确定如何以及无论如何都不容易阅读。

UPDATE 2014: Today we have access to c++11 compilers so you could use a lambda instead, the code would be shorter but have the exact same semantic.

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

回答by akim

The solution proposed by Rob is now valid C++11 (no need for Boost):

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

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

Indeed, as mentioned by Klaim, lambdas are an option, a bit more verbose (you have to "repeat" that the arguments are ints):

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

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

C++14 supports autohere:

C++14auto在这里支持:

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

but still, you declared that arguments are passed by copy.

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

Then the question is "which one is the most efficient". That question was treated by Travis Gockel: Lambda vs Bind. His benchmark program gives on my computer (OS X i7)

那么问题是“哪个最有效”。这个问题由 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

where lambdais a lambda used directly, and lambda boundis a lambda stored in a std::function.

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

So it appears that lambdas are a better option, which is not too much of a surprise since the compiler is provided with higher level information from which it can make profit.

所以看起来 lambda 是一个更好的选择,这并不奇怪,因为编译器提供了更高级别的信息,它可以从中获利。

回答by Rob?

You can use boost::bind:

您可以使用boost::bind

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

回答by PierreBdR

There is a way to do what you want, but you need to use a small adaptor. As the STL doesn't write it for you, can can write it yourself:

有一种方法可以做你想做的,但你需要使用一个小的适配器。由于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); }

Then, you can use it:

然后,您可以使用它:

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

回答by Graham Asher

A very simple way to effectively use a member function is to use operator<. That is, if you have a function called compare, you can call it from operator<. Here is a working example:

有效使用成员函数的一个非常简单的方法是使用 operator<。也就是说,如果您有一个名为 compare 的函数,则可以从 operator< 调用它。这是一个工作示例:

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

Then you don't even need to give the function name to std::sort:

然后你甚至不需要给 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());

回答by Surt

Updating Graham Asher answer, as you don't need the compare but can use the less operator directly.

更新 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;
}

回答by Robin Hsu

The third argument in the calling of std::sort()is not compatible to the function pointer needed by std::sort(). See my answer to another questionfor a detailed explanation for why a member function signature is different from a regular function signature.

调用中的第三个参数与std::sort()所需的函数指针不兼容std::sort()。有关为什么成员函数签名与常规函数签名不同的详细解释,请参阅我对另一个问题的回答