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

发布于 2024-08-14 05:23:36 字数 409 浏览 2 评论 0原文

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


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

}; 

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.

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

}; 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

一指流沙 2024-08-21 05:23:36

doCompare 必须是静态。如果 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)); }
}

doCompare must be static. If doCompare needs data from MyClass you could turn MyClass into a comparison functor by changing:

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 doSort missing a return value?

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

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

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)); }
}
就是爱搞怪 2024-08-21 05:23:36

正如 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,代码会更短,但具有完全相同的语义。

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):

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.

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.

装迷糊 2024-08-21 05:23:36

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

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

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

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

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

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

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

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

The solution proposed by Rob is now valid C++11 (no need for 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):

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

C++14 supports auto here:

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)

                        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 lambda is a lambda used directly, and lambda bound is a lambda stored in a 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.

顾北清歌寒 2024-08-21 05:23:36

您可以使用 boost::bind< /a>:

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

You can use boost::bind:

void doSort() {
  std::sort(arr,arr+someSize, boost::bind(&MyClass::doCompare, this, _1, _2));
}
舂唻埖巳落 2024-08-21 05:23:36

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

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:

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)); }
∞觅青森が 2024-08-21 05:23:36

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

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 question for a detailed explanation for why a member function signature is different from a regular function signature.

若能看破又如何 2024-08-21 05:23:36

只需将您的辅助函数设置为静态,您将在排序函数中传递该函数。

例如,

struct Item
{
int val;
int id;
};

//Compare function for our Item struct
static bool compare(Item a, Item b)
{
return b.val>a.val;
}

现在您可以将其传递到排序函数中

just make your helper function, static which you are going to pass inside the sort function.

for e.g

struct Item
{
int val;
int id;
};

//Compare function for our Item struct
static bool compare(Item a, Item b)
{
return b.val>a.val;
}

Now you can pass this inside your sort function

浅暮の光 2024-08-21 05:23:36

有效使用成员函数的一个非常简单的方法是使用运算符<。也就是说,如果你有一个名为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;
};

那么您甚至不需要将函数名称提供给 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());

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:

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::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());
那片花海 2024-08-21 05:23:36

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

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

#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;
}
2024-08-21 05:23:36

有人可以举一个例子,其中比较函数用于设置。例如

#include <map>
#include <set>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

struct MyStruct {
    unsigned p;
    unsigned t;
};


class MyClass {
public:
    void call() {
        ob["o1_10"] ={10, 1};
        mbp[ob["o1_10"].p].insert("o1_10");

        ob["o2_20_2"] ={20, 2};
        mbp[ob["o2_20"].p].insert("o2_20");

        ob["o3_30"] ={30, 3};
        mbp[ob["o3_30"].p].insert("o3_30");

        ob["o4_4_4"] ={4, 4};
        mbp[ob["o4_4"].p].insert("o4_4");

        ob["o5_10"] ={10, 4};
        mbp[ob["o5_10"].p].insert("o5_10");
    }
    
    
private:
    map<unsigned,set<string, compare>> mbp;
    // Question: how to define compare using struct, operator(), statice metthod or external method so that
    //           compare fetches ob[ol] and ob[0l2] and decide based on some rules
    //           so, comparions is not based on ol and o2 and it is based on some p and t in ob[o1] and ob[02]
    // static bool compare2(string& o1, string& o2) {
    //     // TODO: iS it possible to use this as customed comparison for set in mbp?
    //     // if (this->ob[ol].p > ob[o2].p)   return true;
    //     // if (ob[ol].p == ob[o2].p && ob[ol].t < ob[o2].t) return true;

    //     return false;

    // }
    
    map<string, MyStruct> ob;
};


int main() {
    MyClass my_class;
    my_class.call();

   
    
    return 0;
}

can some one give an example where comparison function is to be used for set. for example

#include <map>
#include <set>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

struct MyStruct {
    unsigned p;
    unsigned t;
};


class MyClass {
public:
    void call() {
        ob["o1_10"] ={10, 1};
        mbp[ob["o1_10"].p].insert("o1_10");

        ob["o2_20_2"] ={20, 2};
        mbp[ob["o2_20"].p].insert("o2_20");

        ob["o3_30"] ={30, 3};
        mbp[ob["o3_30"].p].insert("o3_30");

        ob["o4_4_4"] ={4, 4};
        mbp[ob["o4_4"].p].insert("o4_4");

        ob["o5_10"] ={10, 4};
        mbp[ob["o5_10"].p].insert("o5_10");
    }
    
    
private:
    map<unsigned,set<string, compare>> mbp;
    // Question: how to define compare using struct, operator(), statice metthod or external method so that
    //           compare fetches ob[ol] and ob[0l2] and decide based on some rules
    //           so, comparions is not based on ol and o2 and it is based on some p and t in ob[o1] and ob[02]
    // static bool compare2(string& o1, string& o2) {
    //     // TODO: iS it possible to use this as customed comparison for set in mbp?
    //     // if (this->ob[ol].p > ob[o2].p)   return true;
    //     // if (ob[ol].p == ob[o2].p && ob[ol].t < ob[o2].t) return true;

    //     return false;

    // }
    
    map<string, MyStruct> ob;
};


int main() {
    MyClass my_class;
    my_class.call();

   
    
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文