2017-02-17 76 views
0

以下聲明在聲明3.8.1中失敗,但似乎在其他測試編譯器(例如gcc 6.1,MSVC 2015,clang 3.9.1)中沒有錯誤地編譯。constexpr實例的初始化(例如`std :: integral_constant`)是否需要`= {}`?

constexpr std::integral_constant<int,0> myConstant; 

鐺3.8.1給出:

error: default initialization of an object of const type 'const std::integral_constant<int, 0>' without a user-provided default constructor constexpr std::integral_constant<int,0> myConstant;

而下面的測試中所有的編譯器編譯正確:

constexpr std::integral_constant<int,0> myConstant = {}; 

這到底是怎麼回事? (是鏗鏘3.8.1錯誤是否正確?)

如果我定義我自己的類型,我應該寫一個用戶提供的默認ctor,以便用戶可以避免鍵入={}

回答

1

constexpr變量必須被初始化。表格Typename variablename;的聲明將在variablename上執行默認初始化。

沒有簡單默認構造函數的類型將在默認初始化下爲未初始化。通常這很好。

但是constexpr變量不允許未初始化。因此,對於具有簡單默認構造函數的類型,您必須明確地初始化它們。通過對變量執行= {},您將導致它被初始化爲值,這會將對象清零。

這不應該被認爲是一個問題。一般來說,你應該總是明顯地初始化一個constexpr變量,即使它只是= {}。這樣,每個人都清楚你在做什麼。

不,你不應該添加默認的構造函數類型只是爲了讓人們可以使他們的變量constexpr沒有明顯的初始化它們。如果類型需要一個才能完成其工作,則只應將用戶提供的默認構造函數添加到類型中。


至於編譯器的行爲,就在他們身上。 Clang在3.8.1中的行爲在規範方面是正確的,所以其他人是不正確的。

+0

'std :: integral_constant'沒有值表示(它是一個空的結構體)。你的「你應該總是明顯地初始化」規則是否仍然適用? –

+0

@RossBencina:「* std :: integral_constant沒有值表示*」標準很清楚,所有'constexpr'變量都應該被初始化。它是否具有價值表現並不是標準關心的問題。在constexpr函數中聲明的任何變量也是如此。 –

+0

這個答案目前沒有解決我的問題「這是怎麼回事?」 - 爲什麼不同編譯器之間的行爲不同?哪個編譯器是正確的? –

0

根據這個答案:https://stackoverflow.com/a/28338265/2013747,是否需要={}是一個公開的問題,clang和gcc最初選擇了不同的實現方式。允許省略={}似乎是CWG首選的方向,並且第3.9節改變了政策以反映這一點。

報價CWG活躍的問題#253:

253.爲什麼必須清空或完全初始化const對象初始化?的8.6

[]

第9段[dcl.init]表示:

如果對象沒有指定初始化,並且該對象是(可能> CV修飾)非POD的類類型(或其數組),對象應該>默認初始化;如果對象是const限定類型的,則底層的>類類型應該有一個用戶聲明的默認構造函數。否則,如果沒有爲對象指定初始值設定項,則該對象及其子對象(如果有)具有不確定的初始值;如果該對象或其任何子對象都是const限定類型的,則該程序不合格。

如果const POD對象沒有非靜態數據成員會怎麼樣? 這一措詞需要這樣的情況下一個空的初始化[...]

(強調)。這裏的結論是,與舊的編譯器的兼容性,並嚴格遵守標準,={}必須使用,除非有一個用戶聲明的默認ctor。

舊的叮噹行爲源於語言規範的上述保守解釋 。 CWG 2011年8月的會議解決:從八月

注意,2011會議:

如果隱含的默認構造函數初始化所有子對象,應該不需要初始化。

來源:http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#253

據我所知,這種變化還沒有被納入C++標準的任何版本。因此,雖然省略={}可能會繼續編譯,並且將來可能會被該標準正式支持,但它目前不是官方ISO標準的一部分。