再開一個討論區,C++11的std::function和template function的比較?


同樣的參數和返回值類型的兩個函數對象,類型可能完全不一樣。

std::function最大的特點是類型擦除,它可能的實現方式就是內部有一個多態的指針。

類型擦除大多數情況都沒有必要,比如標準庫里凡是函數作為參數的地方都是用的模板

template&< class RandomIt, class Compare &>
void sort( RandomIt first, RandomIt last, Compare comp );

類型擦除的好處之一是可以把各種奇奇怪怪的類型可以放到一個容器里,比如下面這個容器可以裝很多個各種各樣的lambda,這是怎麼套模板都套不出來的

std::unordered_map&&> handlers;

還可以寫一些沒什麼用的奇奇怪怪的東西

// template&
// int fac_rec(int n, Func cont) {
// 寫成上面這樣過不了編譯
int fac_rec(int n, std::function& cont) {
if(n == 0) {
return cont(1);
} else {
return fac_rec(n - 1, [n, cont](int m) {
return n * cont(m);
});
}
}

int fac(int n) {
return fac_rec(n, [](int m) {
return m;
});
}

性能上,大多數情況是靜態的模板更好,但也有例外,如果模板實例化的版本太多,導致編譯出的機器碼太大,會對指令cache不友好。


c++ - std::function vs template

這個答案應該對你有幫助。

不過這個答案只是從設計和性能的純技術角度做出了分析,下面我來從另一個角度分析這個問題:C++11的新語法對程序員的引導和規範作用。也就是說,為什麼C++11要加入std::function?

std::function,說白了,就是把函數對象化了。

即,你可以把函數視作一個class的object只不過這個object有點特殊:它是一個可調用的對象(重載了operator() )。

為了實現函數對象化,標準里加入了std::function,std::bind,還有lambda,還有mem_fn等。

那麼把函數對象化的目的是什麼呢?

就是為了進一步深化以數據為中心(封裝)的面相對象思想。(連函數都對象化了)

換句話說,在C++11下,我們期望看到更多的泛型演算法,而不希望看到以前的那種用函數去操作數據的代碼了。由於我們現在甚至可以把函數都當作對象去處理了,所以這種期望成為了可能。

比如,我們希望通過std::function等新語法,引導程序員寫出這樣的代碼:

array& stringArr3 = {"ab", "def", "hello"};
auto func = [](const string str1, const string str2){ return str1.size() &< str2.size(); }; sort(stringArr3.cbegin(), stringArr3.cend(), func);

而不希望看到你寫個什麼for循環然後再去排序。

函數對象化的威力是強大的,你甚至可以把成員函數作為可調用的對象

比如,

find_if(stringArr3.cbegin(), stringArr3.cend(), mem_fn(string::empty));

請注意:empty只是string類的非static成員函數。

但是,如最一開始的鏈接里說的那樣,std::function的執行時間代價很大(這很好理解,因為要根據函數生成一個可調用的class然後再實例化出一個對象然後再調用它)。所以說,到處都用std::function是一件很糟糕的事情。

總結:只有在使用泛型演算法或者一些比較特殊的情況下才應該使用std::function,其它情況---"比如即使要寫callback(函數的參數是callback函數),那麼除非你要保證這個函數可以接受任何形式的函數(包括可調用對象、lambda等),否則依然建議使用函數指針、模板",還是應該用傳統的方法。

===============================================================

我還是澄清一下:如果我引用了別人的東西,我是會註明的。


一樓說的比較詳細了,應該是引用了stackoverflow的答案。

說一說我個人在做design的時候的感覺吧。

首先,std::function最強大的功能就是wrapper功能。而打包的對象可以是任何東西。比如function pointer, function object(functor),以及template。傳統的C用法以function pointer為主,但是有時會造成調用時context的混亂,但是效率比較高。而template,一定要先定義再使用,因此C++11加入了lambda function。在某些綁定引用參數使用的情況下,大大簡化了代碼。

現在假想一種情況,也是個人覺得比較有代表性的例子。在做abstract factory pattern design的時候,會有很多子類並行,或者子類的子類並行。當需要建立一條通信管道的時候,比如抓取信息和釋放信息,或者初始化信息的時候,當然,每種信息都有自己特殊額屬性。而每一種信息都是一個繼承類。但父類可能不同。這個時候就不能簡單粗暴地利用class的多樣性解決問題了。而std::function就是一個不錯的選擇。在這種情況下,std::function就是不可代替的。


如果是需要編譯期的綁定方便以後擴展並且對效率要求極高,可以用template,其他的時候就function吧...


這個問題有點怪啊,callback為什麼要和inline能力對比起來?需要callback的時候誰會抱怨不能inline?


推薦閱讀:

為什麼Visual Studio系列產品基本不做防盜版?
用vc++編寫窗口程序,控制多軸運動。類似於實現PLC串口通信之類的。應該學習那方面的知識,怎麼快速入手呢?
Windows 7 和 Windows XP 哪個對 VC6.0 的支持好?
為什麼VS對C++11 C++14的特性支持的那麼慢?
為什麼MSVC中的rand函數非常慢?

TAG:C | CC | VisualC | C標準 | C應用 |