2017-04-01 67 views
4

我想選擇取決於一些有條件的拉姆達,但是編譯器,對於一些lambda表達式表示,該類型的lambda表達式不三元運算符的分支之間匹配。爲什麼在三元運算符分支之間返回lambdas適用於某些lambdas?

下面的代碼編譯:

int flag = 4; 
auto result = flag % 2 
    ? [](int x) { 
     return x + x; 
    } 
    : [](int x) { 
     return x * x; 
    }; 

但下面的2段不進行編譯:

int flag = 4; 
auto result = flag % 2 
    ? [flag](int x) { 
     return x + flag; 
    } 
    : [flag](int x) { 
     return x - flag; 
    }; 

auto result2 = flag % 2 
    ? [](auto x) { 
     return x + x; 
    } 
    : [](auto x) { 
     return x * x; 
    }; 

導致以下錯誤分別是:

test.cpp: In function 'auto f(int)': 
test.cpp:8:9: error: operands to ?: have different types 'f(int)::<lambda(int)>' and 'f(int)::<lambda(int)>' 
     ? [flag](int x) {  

test.cpp: In function 'auto f(int)': 
test.cpp:10:9: error: operands to ?: have different types 'f(int)::<lambda(auto:1)>' and 'f(int)::<lambda(auto:2)>' 
     ? [](auto x) { 
     ^

爲什麼做的最後一2個片段不能編譯?

+5

說「錯誤」時請附上確切消息。 –

+0

順便說一句,作爲一種解決方法,你可以明確地將至少一個lambda轉換爲'std :: function '。 –

+0

我該如何解決lambda具有'auto'參數的最後一個問題? –

回答

7

第一個代碼段編譯,因爲兩者的lambda是隱式轉換爲int(*)(int),所以編譯器可使用作爲?:表達式的類型,從而推斷出的result類型。

如果捕獲列表是非空的(情況2),則不存在指向函數的轉換(N4141中的5.1.2/6),所以我們最終得到兩個不相關的類型,沒有共同的隱式轉換目標作爲operator?:的第二和第三操作數,因此三元表達式的類型不能再被推導出來。

如果3,我們有一個通用的λ,其中,如果捕獲列表是空的,具有轉換運營商,所謂的發明模板參數列表定義了一組可能的轉換。在我們這裏的具體情況,一般的lambda表達式可以轉換爲T2(*)(T1),其中T1是推導出參數的類型和T2是拉姆達的推斷返回類型。長話短說:沒有規則可以從該集合中選擇「最佳轉換」,因此編譯器無法爲我們的三元表達式推導出一種類型。

+1

好吧,無捕獲的泛型lambdas確實具有轉換爲函數指針的功能;問題在於它們可以很好地轉換爲與它們的簽名匹配的每種函數指針,所以你會得到一個含糊不清的結果。 –

+0

@ T.C。修正了,謝謝你的發現。 –

3

三元表達式類型是真假兩分支中的常見類型。運算符試圖通過使用複雜的規則來嘗試轉換兩個分支來查找此類型。但是兩種不同的lambda具有不同的,不同的,不兼容的類型。一般來說,他們不能相互轉換,所以你有第二次和第三次嘗試的呃。

然而,某些種類的lambda(非campuring,非模板化)可以被轉換爲一個函數指針。如果有兩個lambda表達式,可轉換爲相同的函數ponter類型,則三元運算符將推斷該指針爲常見類型。

相關問題