我試圖揭露傳遞的std ::功能<bool (int)>通過值
typedef std::function<bool (int)> Filter;
是
#include <functional>
這樣的一部分用戶可以創建過濾器,並將其傳遞到我的處理組件。該要求要求處理不能在模板化功能中完成。
我知道在接口上使用STL並不是一種好的做法,因爲Filter類型的大小是STL實現相關的。我的替代選項是什麼,但對於原始函數指針或仿函數接收到仿函數。
我試圖揭露傳遞的std ::功能<bool (int)>通過值
typedef std::function<bool (int)> Filter;
是
#include <functional>
這樣的一部分用戶可以創建過濾器,並將其傳遞到我的處理組件。該要求要求處理不能在模板化功能中完成。
我知道在接口上使用STL並不是一種好的做法,因爲Filter類型的大小是STL實現相關的。我的替代選項是什麼,但對於原始函數指針或仿函數接收到仿函數。
大小,如果不是真的很這裏重要的,但你是對的,如果有人使用你的庫使用不同的實現STL的,那麼它將無法使用你的代碼,所以有什麼其他選擇?我會用這個接口(純虛類):
struct MyCallback {
virtual bool filter(int) = 0;
};
class MyImplementation {
public:
...
void set_callbacks(MyCallback*);
};
使用這種架構可以讓你的用戶使用的C++,並在同一時間的權力,你不依賴於STL!
您可以傳遞函數指針作爲std::bind
的結果。例如:
typedef std::function<bool (int)> Filter;
bool Foo(int i)
{
return i == 0;
}
void BarCaller(Filter bar) //pass by value
{
bar(2);
}
Filter bar = std::bind(&Foo, std::placeholders::_1); //now you can pass bar wherever you want
BarCaller(bar);
C風格的回調接口通常通過傳遞兩個值 - 一個函數指針和一個用戶數據指針來完成。如果你願意的話,你可以把它包裝在一個結構體中。
所以,如果你想讓你的dll界面保持C風格,請提供一種方法來包裝std::function
。喜歡的東西:
bool c_style_callback(void *userdata, int n) {
return (*static_cast<const Filter*>(userdata))(n);
}
你可以提供一個頭文件中的便利功能,即在調用的dll運行,並提供你真正想要的界面:
inline void register_callback(const Filter &filter) {
register_c_style_callback(c_style_callback, static_cast<void*>(&filter));
}
我已經懶的和這呼叫者有責任確保filter
只要註冊回叫就保持有效。你可以通過動態分配它的副本來修復它,並且在回調被註銷時添加代碼來檢索和釋放它(再次,這個代碼在調用DLL中運行)。如果取消註冊是由調用者發起的,那麼您需要某種代表註冊回調的句柄。
如果Filter
是一個傳遞給算法的謂詞,在返回後不會再使用它,那麼懶惰就會帶來回報。只有當過濾器無限註冊時,您才需要整個機制來管理生命週期。
史蒂夫,我看到的唯一問題是醜陋的看起來 「void *」 我知道這是C風格的回調和無效*是麪包和黃油。我希望有更優雅的東西。 +1的努力。謝謝。 – Ram
你的問題並不清楚,究竟是什麼問題?什麼都不行,你想做什麼? – Xeo
「*我有什麼替代選項,但是... *」您可以實現您自己的'std :: function'版本。另外,「*我明白,在接口上使用STL並不是一種好的做法,因爲Filter類型的大小是STL實現的依賴。」爲什麼這一點至關重要?誰在乎'std :: function'有多大?由於對象的大小,您的代碼不會失敗。接口的唯一問題來自* dll *接口,其中C++基本上是禁止的。 –
@Nicol:有趣的是BigBoss不同意,並準備在界面中使用有限的C++。基本上,他願意承擔一個ABI,允許具有虛擬功能的班級,但不會規定整個標準庫的佈局。 –