2009-12-14 181 views
22

試圖編譯下面的代碼我得到這個編譯錯誤,我該怎麼辦?使用成員函數作爲比較器排序問題


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

}; 
+0

確切的重複http://stackoverflow.com/q/639100/627163;然而,這裏以更簡潔的方式提出。 – Daniel 2012-11-23 20:03:39

回答

25

doCompare必須static

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

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

,並呼籲:如果從MyClassdoCompare需要的數據,你可以通過改變轉MyClass成對比仿

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

該解決方案仍然存在問題。 STL排序調用傳遞給它的對象的解構器作爲比較器,這會毀掉我的程序! – Navid 2009-12-14 20:06:27

+1

@Navid看看我編輯的答案。 – 2009-12-15 07:15:36

13

由於安德烈亞斯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來代替,代碼會更短,但語義完全相同。

+0

最後,我找到了一個明智的解釋如何做到這一點..!謝謝。 – porgarmingduod 2011-03-30 07:15:03

+0

非常好 - 這可以很容易地適應一個類ptr +方法ptr的通用解決方案。 – tenfour 2011-10-28 14:39:25

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

您可以使用boost::bind

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

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直接使用,並且lambda bound是存儲在一個std::function拉姆達。

所以看來lambda是一個更好的選擇,這並不令人驚訝,因爲編譯器提供了更高級別的信息,可以從中獲利。

+0

第二個和第三個示例應該使用namespace std :: placeholders;而不是 ; – 2018-01-25 21:41:56

+0

@RuslanZasukhin謝謝,修正。 – akim 2018-01-26 09:01:48

0

有效使用成員函數的一種非常簡單的方法是使用運算符<。也就是說,如果您有一個名爲compare的函數,則可以從運營商<調用它。這是一個工作示例:

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 ::排序:

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()); 
0

更新格雷厄姆灰粉的答案,因爲你不需要比較可以直接使用少運算符。

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