2012-07-10 80 views
6

考慮下面的代碼:Lambda捕獲導致不兼容的操作數類型錯誤?

main() 
{ 
    bool t; 
    ... 
    std::function<bool (bool)> f = t ? [](bool b) { return b; } : [](bool b) { return !b; }; // OK 
    std::function<bool (bool)> f = t ? [t](bool b) { return t == b; } : [t](bool b) { return t != b; }; // error 
} 

當鏗鏘3.1編譯的,非捕獲拉姆達的分配工作,而一個與捕獲失敗:

main.cpp:12:36: error: incompatible operand types ('<lambda at main.cpp:12:38>' and '<lambda at main.cpp:12:71>') 
     std::function<bool (bool)> f2 = t ? [t](bool b) { return t == b; } : [t](bool b) { return t != b; }; // error 
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

爲什麼捕捉相同的變量將導致2個lambda需要不兼容的類型?

回答

12

lambda的類型是「唯一的,非聯合類類型」,稱爲閉包類型。每個lambda被實現爲一個不同的類型,聲明範圍本地,它有一個重載的operator()來調用函數體。

:如果寫:

auto a=[t](bool b){return t==b;}; 
auto b=[t](bool b){return t!=b;}; 

然後編譯器編譯此(或多或少):

class unique_lambda_name_1 
{ 
bool t; 
public: 
unique_lambda_name_1(bool t_) t(_t) {} 
bool operator() (bool b) const { return t==b; } 
} a(t); 
class unique_lambda_name_2 
{ 
bool t; 
public: 
unique_lambda_name_2(bool t_) t(_t) {} 
bool operator() (bool b) const { return t!=b; } 
} b(t); 

a和b具有不同的類型和不能使用在?:運算符中。

但是,§5.1.2(6)說,沒有捕獲的lambda的閉包類型有一個非顯式的公共轉換運算符,它將lambda轉換爲函數指針 - 可以實現非閉包作爲簡單的功能。任何具有相同參數和返回類型的lambda可以轉換爲相同類型的指針,因此三元?:運算符可以應用於它們。

實施例:非捕獲拉姆達:

auto c=[](bool b){return b;}; 

被實現這樣的:

class unique_lambda_name_3 
{ 
static bool body(bool b) { return b; } 
public: 
bool operator() (bool b) const { return body(b); } 
operator decltype(&body)() const { return &body; } 
} c; 

這意味着該行:

auto x = t?[](bool b){return b;}:[](bool b){return !b;}; 

實際上,這意味着:

// a typedef to make this more readable 
typedef bool (*pfun_t)(bool); 
pfun_t x = t?((pfun_t)[](bool b){return b;}):(pfun_t)([](bool b){return !b;}); 
+0

感謝您的詳細解釋。我不知道他們的實施方式不同。現在有道理。 – 2012-07-10 12:24:47