2016-08-02 37 views
11
我有lambda表達式沒有捕獲任何,

爲什麼C++中的拉姆達從來沒有缺省構造

[](){}; 

我有一個模板類,它包含這樣的拉姆達。由於lambda不包含非靜態數據成員,也不包含虛函數,因此它應該是一個空類和DefaultConstructible。它只是一種可用於模板元編程的策略類。我想知道,爲什麼這樣的類不是C++標準默認構造的。

旁註:Understanding how Lambda closure type has deleted default constructor提出了一個不同的問題,雖然標題似乎非常相似。它問如何在沒有可用的默認構造函數的情況下創建一個無狀態的lambda對象。我在問爲什麼沒有可用的默認構造函數。

+2

[This question](http:// stackoverflow。com/questions/32911729/understanding-how-lambda-closure-type-has-deleted-default-constructor)可能是相關的。 –

+0

你會如何默認構建一個lambda? '[] {}'已經構造出一個並給你實例。 – rustyx

+0

@rustyx像這樣:'auto f =()[] {};使用f_t = decltype(f); f_t {};' - 這有效,但是因爲lambda已經刪除了默認的構造函數。 –

回答

5

Lambdas旨在創建然後使用。標準因此說「不,他們沒有默認的構造函數」。唯一的辦法是通過一個lambda表達式或者相同的副本。

他們是而不是意欲爲他們的類型是你保留和使用的東西。這樣做可能會違反ODR的規定,並且要求編譯器避免ODR違規,這會使符號過度複雜化。

然而,在C++ 17你可以寫身邊一個函數指針無國籍包裝:

template<auto fptr> 
struct function_pointer_t { 
    template<class...Args> 
    // or decltype(auto): 
    std::result_of_t< std::decay_t<decltype(fptr)>(Args...) > 
    operator()(Args&&...args)const 
    return fptr(std::forward<Args>(args)...); 
    } 
}; 

隨着operator void(*)()[](){}constexpr在C++ 17,function_pointer_t<+[](){}>是一個什麼都不做的函數對象那就是DefaultConstructible。

這實際上並不包含lambda,而是lambda產生的指針函數。

+1

'''function_pointer_t <+[](){}>'中的'+'是故意的,如果是這樣的話,意味着什麼? –

+3

@ PeterA.Schneider它[將空捕獲組的lambdas轉換爲函數指針。](http://stackoverflow.com/questions/18889028/a-positive-lambda-what-sorcery-is-this) – jaggedSpire

+0

好吧,我試過了你的解決方案但是我有了C++ 17可用,它不起作用。首先它偶然發現'template ',我可以通過使用'void(*)()'類型來解決這個問題。然而,編譯器抱怨'function_pointer_t <+[](){}>'在模板參數(GCC)中使用lambda表達式,或者lambda表達式可能不出現在常量表達式(Clang)中。這是由於GCC 6.1和Clang 3.8關於C++ 17的不完整性,還是Yakk的答案不符合C++ 17標準? –

1

我假設你熟悉類型,對象和表達式之間的區別。在C++中,λλ具體指的是λ表達式。這是一個方便的方式來表示一個非平凡的對象。但是,它很方便:您可以通過編寫代碼自己創建一個類似的對象。

現在,根據C++規則,每個表達式都有一個類型,但該類型不是lambda表達式的目的。這就是爲什麼它是一個未命名和獨特的類型--C++委員會認爲不值得定義這些屬性。同樣,如果它被定義爲具有默認ctor,則標準應定義該行爲。根據目前的規則,不需要定義默認ctor的行爲。

正如你所注意到的,對於[](){}的特殊情況,定義一個默認ctor是很簡單的。但這沒有意義。你馬上就會遇到第一個難題:爲什麼lambda應該定義默認的ctor?什麼lambda的子集足夠簡單,有一個體面的定義,但足夠複雜,有趣?沒有一致意見,你不能期望這是標準化的。

請注意,作爲擴展的編譯器供應商已經可以提供此功能。標準化通常遵循現有的做法,參見Boost。但是,如果沒有編譯器供應商個人認爲這是值得的,他們爲什麼一致認爲這麼做?

+0

實際上,您可以將lambda看作是一個對象,它是由將捕獲列表作爲構造函數參數的構造函數創建的。具有空捕獲列表的lambda自然應該有一個默認的構造函數恕我直言。 –