2012-10-12 28 views
1

我試圖揭露傳遞的std ::功能<bool (int)>通過值

typedef std::function<bool (int)> Filter; 

#include <functional> 

這樣的一部分用戶可以創建過濾器,並將其傳遞到我的處理組件。該要求要求處理不能在模板化功能中完成。

我知道在接口上使用STL並不是一種好的做法,因爲Filter類型的大小是STL實現相關的。我的替代選項是什麼,但對於原始函數指針仿函數接收到仿函數。

+1

你的問題並不清楚,究竟是什麼問題?什麼都不行,你想做什麼? – Xeo

+1

「*我有什麼替代選項,但是... *」您可以實現您自己的'std :: function'版本。另外,「*我明白,在接口上使用STL並不是一種好的做法,因爲Filter類型的大小是STL實現的依賴。」爲什麼這一點至關重要?誰在乎'std :: function'有多大?由於對象的大小,您的代碼不會失敗。接口的唯一問題來自* dll *接口,其中C++基本上是禁止的。 –

+0

@Nicol:有趣的是BigBoss不同意,並準備在界面中使用有限的C++。基本上,他願意承擔一個ABI,允許具有虛擬功能的班級,但不會規定整個標準庫的佈局。 –

回答

2

大小,如果不是真的很這裏重要的,但你是對的,如果有人使用你的庫使用不同的實現STL的,那麼它將無法使用你的代碼,所以有什麼其他選擇?我會用這個接口(純虛類):

struct MyCallback { 
    virtual bool filter(int) = 0; 
}; 
class MyImplementation { 
public: 
    ... 
    void set_callbacks(MyCallback*); 
}; 

使用這種架構可以讓你的用戶使用的C++,並在同一時間的權力,你不依賴於STL!

1

您可以傳遞函數指針作爲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); 
+0

這是多餘的,'std :: function'完全有能力處理函數指針。 – Xeo

+0

他試圖通過價值傳遞他們,因爲我理解並展示瞭如何實現它 –

+0

正如我所理解的問題,它確實是關於如何聲明'BarCaller',因此它不接受'std :: function ' ,也不是模板參數,也不是裸函數指針。 – jogojapan

1

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是一個傳遞給算法的謂詞,在返回後不會再使用它,那麼懶惰就會帶來回報。只有當過濾器無限註冊時,您才需要整個機制來管理生命週期。

+0

史蒂夫,我看到的唯一問題是醜陋的看起來 「void *」 我知道這是C風格的回調和無效*是麪包和黃油。我希望有更優雅的東西。 +1的努力。謝謝。 – Ram