2009-12-18 101 views
43

我有一個關於哪種風格是首選的問題:std :: bind Vs lambda in C++ 0x。我知道他們服務於某些目的 - 不同的目的,但讓我們舉一個相交功能的例子。綁定與Lambda?

使用lambda

uniform_int<> distribution(1, 6); 
mt19937 engine; 
// lambda style 
auto dice = [&]() { return distribution(engine); }; 

使用bind

uniform_int<> distribution(1, 6); 
mt19937 engine; 
// bind style 
auto dice = bind(distribution, engine); 

哪一個我們應該更喜歡哪個?爲什麼?假設比上述例子更復雜的情況。即彼此的優點/缺點是什麼?

+1

是否有任何性能差異?速度,內存消耗,堆使用率? – 2009-12-19 03:33:44

+0

@Caspin我不知道這兩個工具之間的性能/內存消耗是否有差異:) – AraK 2009-12-19 04:54:38

+4

btw:這兩個版本並不相同,因爲綁定複製參數。替代方法:bind(ref(distribution),ref(engine)) – sellibitze 2009-12-19 10:32:08

回答

22

正如你所說,綁定和lambda不完全針對相同的目標。例如,對於使用和組合STL算法,lambda是清晰的贏家,恕我直言。爲了說明這一點,我記得有一個非常有趣的答案,在堆棧溢出問題上,有人提出了十六進制幻數的想法(如0xDEADBEEF,0xCAFEBABE,0xDEADDEAD等),並被告知如果他是一個真正的C++程序員他也只會下載的英語單詞列表,並使用C++一個簡單的一行:)

#include <iterator> 
#include <string> 
#include <algorithm> 
#include <iostream> 
#include <fstream> 
#include <boost/lambda/lambda.hpp> 
#include <boost/lambda/bind.hpp> 

int main() 
{ 
    using namespace boost::lambda; 
    std::ifstream ifs("wordsEn.txt"); 
    std::remove_copy_if(
     std::istream_iterator<std::string>(ifs), 
     std::istream_iterator<std::string>(), 
     std::ostream_iterator<std::string>(std::cout, "\n"), 
     bind(&std::string::size, _1) != 8u 
      || 
     bind(
      static_cast<std::string::size_type (std::string::*)(const char*, std::string::size_type) const>(
       &std::string::find_first_not_of 
      ), 
      _1, 
      "abcdef", 
      0u 
     ) != std::string::npos 
    ); 
} 

這個片段中,在純C++ 98,打開英語單詞文件,掃描每個字並打印'a','b','c','d','e'或'f'字母的長度爲8的字母。

現在,打開的C++ 0x和lambda:

#include <iterator> 
#include <string> 
#include <algorithm> 
#include <iostream> 
#include <fstream> 

int main() 
{ 
std::ifstream ifs("wordsEn.txt"); 
std::copy_if(
    std::istream_iterator<std::string>(ifs), 
    std::istream_iterator<std::string>(), 
    std::ostream_iterator<std::string>(std::cout, "\n"), 
    [](const std::string& s) 
    { 
     return (s.size() == 8 && 
       s.find_first_not_of("abcdef") == std::string::npos); 
    } 
); 
} 

這仍然是一個有點重(這主要是因爲istream_iterator業務)來讀取,但比綁定版本簡單得多:)

+0

儘管這兩段代碼不會做同樣的事情,但我的觀點非常清楚:) – AraK 2009-12-19 04:56:38

+4

lambda應該是:[](const std :: string&s) - > bool – 2009-12-19 11:00:53

+9

@Beh Tou Cheh I認爲如果lambda包含'return ;'only(如Thomas所做的那樣),則應該推斷出該類型。 – AraK 2009-12-19 11:09:48

17

C++ 0x lamdba語法比綁定語法更具可讀性。一旦進入超過2-3級的綁定,你的代碼就變得難以理解,難以維護。我更喜歡更直觀的lambda語法。

+0

不同意。 '[this](){Type * this_too = this; run([this_too](){this_too-> f();});}'既不可讀也不直觀。 – 2015-02-25 12:55:28

+5

無可否認,我認爲新的行會幫助你的反例。新行對綁定沒有多大幫助。 – 2016-07-21 18:08:19

3

我認爲這更多的是品味的問題。快速掌握新技術或熟悉函數式編程的人可能更喜歡使用lambda語法,而更保守的程序員肯定會更喜歡綁定,因爲它更像傳統的C++語法。

這樣的決定應該與那些將與代碼一起工作的人協調,可能是通過多數票。

但是,這並沒有改變這個事實,即lambda語法更加強大和更清晰。

+3

團隊中的人不斷變化。代碼可讀性尤其重要。爲未來的維護程序員。因此,我們應該選擇提供更多可讀性的解決方案,在lamdba和bind之間,lamda肯定會拿到蛋糕。 – posharma 2009-12-18 22:25:24

8

lambda表達式的好處之一是,當你需要在現有函數之上添加一些邏輯時,它們會更有用。

使用綁定,即使邏輯在這一個地方只被需要,你也不得不創建一個新的函數/方法/仿函數。你需要提出一個合適的名稱,並且可能會使代碼變得不那麼容易理解,因爲它可能會讓你分解相關的邏輯。

使用lambda,您可以在lambda內添加新邏輯(但如果創建新的可調用函數有意義,則不會強制執行)。

+1

+1。我不得不在dtor中關閉一個FILE *向量。而不是能夠使用lambda'[](FILE * f){if(f)fclose(f); }'我必須創建一個命名函數並使用它。該函數出現在類的'private'部分,因此被'for_each'調用的多行分隔 – KitsuneYMG 2009-12-19 09:15:39

0

C++ 0x lambdas基本上替換綁定。沒有什麼可綁定的,你不能重新創建一個簡單的包裝lambda來實現相同。一旦lambda支持廣泛傳播,std :: tr1 :: bind就會成爲std :: bind1st等等。這很好,因爲大多數程序員因爲某種原因而難以獲得綁定的頭腦。

+3

雖然這個答案在發佈時不正確,但它對於C++ 14來說是準確的。上面評論中的鏈接現在證實了這一點。 – 2016-05-24 04:29:53

+0

@gnzlbg請參閱上面的評論。 – 2017-01-17 15:11:54

39

C++ 0x lambdas是單形的,而bind可以是多態的。你不能有像

auto f = [](auto a, auto b) { cout << a << ' ' << b; } 
f("test", 1.2f); 

a和b必須有已知的類型。在另一方面,TR1 /升壓/鳳凰/λ結合可以讓你做到這一點:

struct foo 
{ 
    typedef void result_type; 

    template < typename A, typename B > 
    void operator()(A a, B b) 
    { 
    cout << a << ' ' << b; 
    } 
}; 

auto f = bind(foo(), _1, _2); 
f("test", 1.2f); // will print "test 1.2" 

注意的是,A型和B 固定在這裏。只有當f被實際使用時,這兩個纔會被推斷出來。

+0

爲什麼不直接用顯式類型參數聲明lambda?這將比上面所示的綁定解決方案有很大的改進。另外,如果你想要複用更復雜的功能,lambda仍然比bind更好,因爲它不需要結構,即使你想將狀態綁定到仿函數中:'template <...> foo(A a,B b,int state){cout ... << state; } ... auto f = [](const char * a,float b){foo(a,b,42); };'。 – 2011-04-07 03:17:09

+2

@Marcelo Cantos:要證明的陳述是「C++ 0x lambdas是單形的」,正是因爲你必須用顯式類型的參數聲明lambda表達式。 – MSalters 2011-04-07 09:15:23

+0

@ MSalters:問題是(大致):「哪個更好?」我不確定如何證明C++ 0x lambda是單形的回答這個問題。 – 2011-04-07 12:17:25