3 回答

TA貢獻1826條經驗 獲得超6個贊
簡而言之,std::function除非有理由不要使用。
函數指針的缺點是無法捕獲某些上下文。例如,您將無法通過lambda函數作為捕獲某些上下文變量的回調(但是如果不捕獲任何上下文變量,它將起作用)。因此也不可能調用對象的成員變量(即非靜態的),因為this需要捕獲對象(-pointer)。(1)
std::function(因為C ++ 11)主要用于存儲函數(將其傳遞就不需要存儲它)。因此,如果要將回調存儲在例如成員變量中,則可能是最佳選擇。但是,如果您不存儲它,那么它是一個不錯的“首選”,盡管它的缺點是在調用時會引入一些(非常小的)開銷(因此,在性能非常關鍵的情況下,這可能是個問題,但在大多數情況下它不應該)。這是非常“通用的”:如果您非常關心一致且易讀的代碼,又不想考慮所做的每一個選擇(即想保持簡單),請使用std::function傳遞的每個函數。
考慮第三個選項:如果您要實現一個小的函數,然后通過提供的回調函數報告某些內容,請考慮一個template參數,該參數可以是任何可調用的對象,即函數指針,函子,lambda,一個std::function缺點是這里的(外部)函數成為模板,因此需要在標頭中實現。另一方面,您得到的好處是可以內聯對回調的調用,因為(外部)函數的客戶端代碼“看到”了對回調的調用,將提供確切的類型信息。
具有模板參數的版本的示例(對于C ++ 11之前的版本,請寫&而不是&&):
template <typename CallbackFunction>
void myFunction(..., CallbackFunction && callback) {
...
callback(...);
...
}
正如您在下表中看到的,它們都有優點和缺點:
+-------------------+--------------+---------------+----------------+
| | function ptr | std::function | template param |
+===================+==============+===============+================+
| can capture | no(1) | yes | yes |
| context variables | | | |
+-------------------+--------------+---------------+----------------+
| no call overhead | yes | no | yes |
| (see comments) | | | |
+-------------------+--------------+---------------+----------------+
| can be inlined | no | no | yes |
| (see comments) | | | |
+-------------------+--------------+---------------+----------------+
| can be stored | yes | yes | no(2) |
| in class member | | | |
+-------------------+--------------+---------------+----------------+
| can be implemented| yes | yes | no |
| outside of header | | | |
+-------------------+--------------+---------------+----------------+
| supported without | yes | no(3) | yes |
| C++11 standard | | | |
+-------------------+--------------+---------------+----------------+
| nicely readable | no | yes | (yes) |
| (my opinion) | (ugly type) | | |
+-------------------+--------------+---------------+----------------+
(1)存在克服此限制的解決方法,例如,將其他數據作為進一步的參數傳遞給您的(外部)函數:myFunction(..., callback, data)will call callback(data)。這就是C樣式的“帶參數的回調”,這在C ++中是可行的(并且在WIN32 API中大量使用),但是應避免使用,因為我們在C ++中有更好的選擇。
(2)除非我們在談論類模板,否則存儲函數的類就是模板。但這意味著在客戶端,函數的類型決定了存儲回調的對象的類型,這在實際用例中幾乎從來不是一個選擇。
(3)對于C ++ 11之前的版本,請使用 boost::function

TA貢獻1796條經驗 獲得超10個贊
使用std::function存儲任意調用對象。它允許用戶提供回調所需的任何上下文。一個普通的函數指針沒有。
如果由于某種原因(也許是因為您想要C兼容的API)而確實需要使用普通函數指針,則應添加一個void * user_context參數,以便至少有可能(盡管不方便)訪問不直接傳遞給參數的狀態。功能。
- 3 回答
- 0 關注
- 1606 瀏覽
添加回答
舉報