2010-11-01 198 views
15

在向量上使用STL排序算法時,我想傳入我自己的比較函數,該函數也需要一個參數。將參數傳遞給比較函數?

例如,最好我想做一個本地函數聲明,如:

int main() { 
    vector<int> v(100); 
    // initialize v with some random values 

    int paramA = 4; 

    bool comp(int i, int j) { 
     // logic uses paramA in some way... 
    } 

    sort(v.begin(), v.end(), comp); 
} 

然而,編譯器會抱怨了一番。當我嘗試類似:

int main() { 
    vector<int> v(100); 
    // initialize v with some random values 

    int paramA = 4; 

    struct Local { 
     static bool Compare(int i, int j) { 
      // logic uses paramA in some way... 
     } 
    }; 

    sort(v.begin(), v.end(), Local::Compare); 
} 

編譯器仍然抱怨:「錯誤:使用參數從包含函數」

我應該怎麼辦?我應該使用全局比較函數來創建一些全局變量嗎?

謝謝。

回答

22

您不能從本地定義的函數內訪問函數的局部變量 - C++在其當前形式中不允許closures。該語言的下一個版本C++ 0x將支持這一點,但語言標準尚未最終確定,目前對草案標準的支持不多。

爲了做到這一點,您應該將std::sort的第三個參數更改爲對象實例而不是函數。 std::sort的第三個參數可以是任何可調用的(即,任何x,其中添加括號如x(y, z)使句法有意義)。要做到這一點,最好的方法是定義一個實現operator()功能的結構,然後傳遞對象的實例:

struct Local { 
    Local(int paramA) { this->paramA = paramA; } 
    bool operator() (int i, int j) { ... } 

    int paramA; 
}; 

sort(v.begin(), v.end(), Local(paramA)); 

請注意,我們必須存儲paramA的結構,因爲我們無法訪問否則從operator()內。

+0

第三個參數是什麼,可以使用函數調用語法來調用。因此,定義'operator()'的函數和類/結構都會起作用。 – 2010-11-01 04:17:46

+0

@Eugen:好點,我已經更新了我的回答以反映這一點。 – 2010-11-01 04:24:10

+0

謝謝,這是工作(除了編譯器抱怨,除非我移動主函數以外的結構聲明,我認爲我們被允許本地聲明類和結構..?) – George41 2010-11-01 04:39:42

10

在C++中,你不能在另一個函數中定義一個自由函數。所以你的第一個代碼片段是不健康的。

sort(v.begin(), v.end(), Local::Compare);

第三個參數必須是一個函數對象。在類中重載()運算符,然後創建函數對象。


在C++ 0x中,您可以使用lambda expressions

auto comp = [&](int m,int n)-> bool { 

     return m<n; //or use paramA in some way 
    }; 

sort(v.begin(), v.end(), comp); 
+0

在我看來,由於使用漂亮的C++特性(lambda),這是一個比例外更好的解決方案, – Anonymous 2015-03-27 12:50:59

4

一種可能性是,當你建立你的比較對象來傳遞參數:

class cmp { 
    int param; 
public: 
    cmp(int p) : param(p) {} 

    bool operator()(int i, int j) { 
     // logic uses param 
    } 
}; 

int main() { 
    vector<int> v(100); 
    // initialize v with some random values 

    int paramA = 4; 

    sort(v.begin(), v.end(), cmp(paramA)); 
}