基本上,我正在實現一個容器類。我需要創建一個方法,根據必須與排序請求一起傳遞的比較函數/函數對數據進行排序。由於該方法的聲明和定義在不同的文件(.h和.cpp)中,所以使用模板成爲一個問題(並且我沒有太多的使用經驗)。換句話說,我想做一個方法:如何創建一個我可以傳遞函數或函子的方法?
void sort(function/functor f);
我不知道如何定義函數。那麼,有沒有解決這個問題的方法?
基本上,我正在實現一個容器類。我需要創建一個方法,根據必須與排序請求一起傳遞的比較函數/函數對數據進行排序。由於該方法的聲明和定義在不同的文件(.h和.cpp)中,所以使用模板成爲一個問題(並且我沒有太多的使用經驗)。換句話說,我想做一個方法:如何創建一個我可以傳遞函數或函子的方法?
void sort(function/functor f);
我不知道如何定義函數。那麼,有沒有解決這個問題的方法?
如果您知道要傳遞的函數/函子的簽名[*],則可以使用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::list
和std::forward_list
。
[*]實際上std::function
不需要完全相同的簽名。您只需說出要調用它的類型以及要將返回值轉換爲的類型。所以如果你用兩個int
來調用它,並且調用者提供了一個需要兩個long
的函數,那就沒問題。參數轉換就像函數調用一樣,沒有任何std::function
。
即使你不知道簽名,你也知道它將如何在你的函數體中被調用。 'std :: function'(我假設'boost ::')將使用它聲明的簽名類型擦除任何* compatible *。 – Yakk
@Yakk:真的,會更新。 –
感謝您的幫助 – user1242967
這通常使用模板完成。就像這樣:
#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());
}
希望它能幫助。
但是否使用模板解決方案在我的情況?我只有在頭文件中進行排序的聲明,.cpp文件包含了實現。據我所知,代碼不會在我的情況下編譯。 – user1242967
@ user1242967:這就是爲什麼我一直在使用'的std :: function'以及提供了一個示例。 – 2013-12-09 20:08:37
您可以使用std::function
在史蒂夫·傑索普的答案,但在這種情況下,我想你應該考慮讓你的排序功能的模板函數在弗拉德的答覆建議。排序函數必須多次調用比較器,並且在這種情況下使用std::function
會有明顯的開銷。
最簡單的解決方法是使用一個模板:如果你想使用指定舊的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.
};
當然,「C」的方式只與功能,不可調用的類對象的工作,使並不適用於這個問題。 –
@MikeSeymour:我不同意。他需要一個函數/函子來允許他對元素進行排序(所以他只需要知道元素類型)。這適用於C風格的功能(儘管這不是我會去的方式)。我錯過了更微妙的東西嗎? –
@LokiAstari:我想提問的意圖是,來電者應當可以自由選擇是否將一個函數或(另)一個函子。並不是容器的作者將它限制在功能上。 –
使用模板不會成爲一個問題 - 請記住,他們(通常)需要在標題中定義。有型擦除的替代品(如'的std :: function'),如果你真的想避免因爲某些原因模板,並且不介意額外的運行時間成本。 –
你的「排序」功能有多大?你有沒有機會向你的容器公開基於迭代器的訪問? – Yakk
基本上,它只是將一個調用委託給標準的排序函數。 – user1242967