2013-12-09 55 views
0

基本上,我正在實現一個容器類。我需要創建一個方法,根據必須與排序請求一起傳遞的比較函數/函數對數據進行排序。由於該方法的聲明和定義在不同的文件(.h和.cpp)中,所以使用模板成爲一個問題(並且我沒有太多的使用經驗)。換句話說,我想做一個方法:如何創建一個我可以傳遞函數或函子的方法?

void sort(function/functor f); 

我不知道如何定義函數。那麼,有沒有解決這個問題的方法?

+0

使用模板不會成爲一個問題 - 請記住,他們(通常)需要在標題中定義。有型擦除的替代品(如'的std :: function'),如果你真的想避免因爲某些原因模板,並且不介意額外的運行時間成本。 –

+0

你的「排序」功能有多大?你有沒有機會向你的容器公開基於迭代器的訪問? – Yakk

+0

基本上,它只是將一個調用委託給標準的排序函數。 – user1242967

回答

4

如果您知道要傳遞的函數/函子的簽名[*],則可以使用std::function。或者如果您沒有C++ 11,請撥打boost::function。因此,對於一個比較器將是:

void sort(std::function<bool(const Element&, const Element&)> f); 

其中Element是所述容器的元件的類型。

如果你不能定義一個具有virtual比較函數的類,並允許調用者用它們自己的類派生它。這對於來電者來說更多的工作,但這正是std::function提供的:呼叫者不必這樣做的一種方式。

兩個警告:

  • 確保有一個真正的好理由你的容器不被在頭文件的執行情況。所有的標準容器都是在頭文件中實現的,而且大多數都能正常工作。

  • 請確保您確實有一個很好的理由來實現sort函數。標準容器只有sort函數,其中std::sort不起作用:std::liststd::forward_list

[*]實際上std::function不需要完全相同的簽名。您只需說出要調用它的類型以及要將返回值轉換爲的類型。所以如果你用兩個int來調用它,並且調用者提供了一個需要兩個long的函數,那就沒問題。參數轉換就像函數調用一樣,沒有任何std::function

+0

即使你不知道簽名,你也知道它將如何在你的函數體中被調用。 'std :: function'(我假設'boost ::')將使用它聲明的簽名類型擦除任何* compatible *。 – Yakk

+0

@Yakk:真的,會更新。 –

+0

感謝您的幫助 – user1242967

2

這通常使用模板完成。就像這樣:

#include <iostream> // For example output only. 

template <typename F> 
void sort(F&& pred) { 
    pred(123); 
} 

void normal_func(int v) { 
    std::cout << "normal_func(" << v << ")\n"; 
} 

struct my_pred { 
    void operator()(int v) const { 
     std::cout << "my_pred(" << v << ")\n"; 
    } 
}; 

int main() { 
    sort([](int v) { std::cout << "Called lambda func with " << v << '\n'; }); 
    sort(normal_func); 
    sort(my_pred()); 
} 

但是,如果不能使用的模板,那麼你最好的選擇將是使用多態函數包裝像std::function(或boost::function,或者你可以寫自己的簡單版本)。

或者,您可以使用硬核C風格的常規函數​​以及用戶可以保存其上下文的void指針。例如,像qsort()。儘管我儘可能不去那裏。

下面是使用std::function一個例子:

#include <iostream> // For example output only. 
#include <functional> // For std::function. 

void sort(const std::function<void(int)>& pred) { 
    pred(123); 
} 

void normal_func(int v) { 
    std::cout << "normal_func(" << v << ")\n"; 
} 

struct my_pred { 
    void operator()(int v) const { 
     std::cout << "my_pred(" << v << ")\n"; 
    } 
}; 

int main() { 
    sort([](int v) { std::cout << "Called lambda func with " << v << '\n'; }); 
    sort(normal_func); 
    sort(my_pred()); 
} 

希望它能幫助。

+0

但是否使用模板解決方案在我的情況?我只有在頭文件中進行排序的聲明,.cpp文件包含了實現。據我所知,代碼不會在我的情況下編譯。 – user1242967

+0

@ user1242967:這就是爲什麼我一直在使用'的std :: function'以及提供了一個示例。 – 2013-12-09 20:08:37

0

您可以使用std::function在史蒂夫·傑索普的答案,但在這種情況下,我想你應該考慮讓你的排序功能的模板函數在弗拉德的答覆建議。排序函數必須多次調用比較器,並且在這種情況下使用std::function會有明顯的開銷。

0

最簡單的解決方法是使用一個模板:如果你想使用指定舊的C符號

class C 
    { 
     template<typename T> 
     void sort(T func) 
     { 
      func(12,45); // Will compile as long as your function/functor 
     }     // Can take two integers as parameters. 
    };      // NOTE: or integers can be converted into your parameters. 

typedef void (*FUNC_TYPE)(int, int); // declares a function pointer type. 
             // returns void takes two integers. 
    class C 
    { 
     void sort(FUNC_TYPE func) 
     { 
      func(12,45);      // Compiles only if the function 
     }          // matches the exact type. 
    }; 

的C++ 11的方式

class C 
    { 
     void sort(std::function<void(int,int)> func) 
     { 
      func(12,45);      // Will match any func/functor that 
              // will return a void and takes two 
     }         // integers. 
    }; 
+0

當然,「C」的方式只與功能,不可調用的類對象的工作,使並不適用於這個問題。 –

+0

@MikeSeymour:我不同意。他需要一個函數/函子來允許他對元素進行排序(所以他只需要知道元素類型)。這適用於C風格的功能(儘管這不是我會去的方式)。我錯過了更微妙的東西嗎? –

+0

@LokiAstari:我想提問的意圖是,來電者應當可以自由選擇是否將一個函數或(另)一個函子。並不是容器的作者將它限制在功能上。 –

相關問題