2017-07-06 136 views
11

如果我理解正確this answer和參考標準節[dcl.type.auto.deduct-5],代碼:在decltype(auto)的情況下是否有lambda的特殊規則?

decltype(auto) a = e; 

總是等同於

decltype(e ) a = e; 

但現在的問題出現,如果不是的e我把lambda表達式decltype(auto)

decltype(auto) lambda = [](){}; 

本編譯,令我驚訝的是,在gccclang都成功。原因我已經經歷了震盪中奠定了標準,具體說是拉姆達不應該在未計算的操作數[expr.prim.lambda#2](重點煤礦)發生:

一個lambda表達式是一個prvalue,其結果對象稱爲 閉包對象。 Lambda表達式不應出現在未評估的 操作數中,模板參數中,別名聲明中,類型聲明 聲明中,或函數或函數模板 聲明的函數體外部和默認值參數。

但正如我所提到的例子是等價於:

decltype([](){}) lambda = [](){}; 

書面明確顯然上面的代碼會形成不良。當然我們可以假設decltype裏面的語句[](){}是一種參考,並不像structured bindings那樣是一個參考,但是在標準中有一個特殊規則,我錯過了包括lambda初始化decltype(auto)

回答

7

這個答案是基於我對相關標準文本的解釋。這些部分對分歧意見不是很清楚,因此目前很難知道它們的確切含義。看起來,除了可能的監督之外,主要的編纂者似乎都認爲,有關的定義確實是完整的。

此外,我認爲聽到這個定義不合格會令人非常驚訝。


原因我所經歷的震盪標準,說具體爲拉姆達不應該在未計算的操作數出現[...]

奠定你在哪裏看到出現一個lambda在未評估的情況下?

decltype(auto) lambda = [](){}; 

我沒有看到它,因爲沒有。 lambda被用作初始化器,這是完全合法的。現在

你的困惑可能來自大約是因爲你似乎認爲,上述說法是相當於

decltype([](){}) lambda = [](){}; 

這不是的情況下,雖然嚴格來說。如果你看一下措辭的語言,有一個小的差異(由我高亮):

如果佔位符是decltype(auto)類型說明符T應單獨佔位符。推導出的T的類型按照[dcl.type.simple]中的描述確定,因爲儘管e已經成爲decltype的操作數。

這裏的關鍵詞是,雖然。這僅表示扣除發生在decltype(e),這意味着decltype的扣除規則適用於操作數eauto的扣除規則。

這裏,操作e的確是拉姆達,但這是完全合法的,因爲標準授權行爲就如同你會寫decltype([](){})相同,這意味着的decltype扣除的規則適用於拉姆達。現在[expr.prim.lambda]/2在這裏不適用,因爲lambda不在未評估的上下文中,所以編譯器使用decltype([](){})推斷該類型實際上是合法的,這意味着必須使用decltype規則用於lambda。

當然,如果你寫decltype([](){}),該程序是不合格的,但在這裏不是這樣,如上所述。

在這種情況下,因爲lambda表達式是一個prvalue,推導的類型應該只是lambda的類型。

至少這就是我所理解它...

+0

好兩種編譯器團隊獨立理解像你這樣有一個巨大的機會,你是對的。儘管如此,如果你說「它不完全等效」,那麼不應該對如何解釋它有嚴格的規定嗎? –

+0

我的意思是 - 它不應該像初始化列表的情況下行事 - 其中'自動x6a = {1,2};'是好的,但'decltype(auto)x6d = {1,2};'不是? –

+1

@ W.F .:「*不應該有如何解釋它的嚴格規定*」有一個嚴格的規則;他只是爲你引用了它。這就是爲什麼「兩個編譯器團隊」是對的。 –