簡體   English   中英

是否有任何C ++標准的計划來解決初始化列表構造函數的不一致性?

[英]are there any plans in C++ standard to address inconsistency of initializer list constructors?

C ++中的初始化列表構造函數經常會引起麻煩; 例如

using std::vector;
using std::string;
vector<string> v{3}; // vector of three empty strings
vector<int> u{3}; // vector of one element with value 3

(只是為了澄清,我的意思是<int>構造函數是一個初始化列表構造函數,而<string>一個不是 。)

int case匹配初始化列表構造函數,而string case不匹配。 這有點難看,常常會造成麻煩。 在Scott Meyers的Effective Modern C ++的早期章節(第7項)中也注意到了這一點,並且他將其描述為標准中有些不愉快的部分,每當初始化列表構造函數可用時,編譯器將跳過箍嘗試匹配它,優先於每個其他構造函數。

當然,通過將u{3}更改為u(3)可以很容易地修復int情況,但這不是重點。

這是理想的行為嗎? C ++標准委員會是否有任何討論或計划來解決這種模糊/不愉快? 一個例子是要求初始化程序列表構造函數被調用如下: vector<int> u({3}) ,它已經是合法的。

C ++標准委員會是否有任何討論或計划來解決這種模糊/不愉快?

自C ++ 11以來,已有許多初始化修復。 例如,您最初無法使用列表初始化( CWG 1467 )復制構造聚合。 這個非常小的修復程序以一種不合需要的方式破壞了一些代碼,導致出現一個新問題,如果有一個initializer_list構造函數( CWG 2137 ),則需要優化以前的修復程序以撤消它。 即使在小的情況下,也很難觸及這些條款中的任何內容而不會產生許多意外后果和破壞代碼。 我懷疑將來會對初始化進行任何大的改動。 此時,代碼破壞的數量將是巨大的。

最好的解決方案就是要了解初始化的缺陷,並注意你正在做的事情。 我的經驗法則是當我故意需要{}提供的行為時使用{} s,否則使用()

請注意,這與以下更為人熟知的陷阱沒有任何不同:

vector<int> a{10}; // vector of 1 element
vector<int> b(10); // vector of 10 elements

一個例子是要求初始化程序列表構造函數被調用如下: vector<int> u({3}) ,它已經是合法的。

你有同樣的問題,原因相同:

vector<int> u({3});    // vector of one element: 3
vector<string> v({3}); // vector of three elements: "", "", and ""

即使你要求前者(這是不可能的),也不能使后者形成錯誤。

首先是一個統一的初始化器,它被引入來解決語言的歧義。 這個問題被稱為Most Vexing Parse與聲明變量有關,由“round”()括號初始化。 MVP是代碼中的一種模糊度解析,類似於以下內容:

class  SomeInitClass;


void  bleh()
{
       int foo(SomeInitClass());
}

foo這里實際上是一個函數的原型,它將一個函數作為參數返回一個Bar,而foo函數的返回值是一個int 基本上,如果某些東西看起來像原型,C ++就會這樣對待它。

int foo{SomeInitClass{}};

SomeInitClass{}總是會創建一個臨時的。 int foo{...}總是會創建一個變量。

雖然這兩行的工作方式不同:

vector<string> v{3}; // vector of three empty strings
vector<int> u{3}; // vector of one element with value 3

他們承擔相同的語義,它們的變量聲明。 它的工作方式(事實上你可以聲明構造函數將初始化列表作為參數)確實對C ++語言有很大的意義,C ++語言采用隱藏其語法背后的真值和操作量的概念。

這不是矛盾,至少不是主要的。 vector<string>vector<int>不是同一個類,並且沒有相同的構造函數,因為它們不是模板std :: vector的相同實例。 為了避免混淆,可以使用別名並使用稍微不同的語法。

 StringCollecton v{3}; //three strings;
 IntCollection   u = {3}; // or {{3}}

當然, StringCollecton test = {3}; 在這種情況下將不起作用,因為3不是可以被轉換為適當存儲類型的文字。

因為在聲明中只能有一個初始化器,所以創建的字符串容器的設置值看起來如下:

std::vector<std::string> test{3, {"string"}}; // all values initialized by "string"

std::vector<std::string> test{{"string1","",""}}; // constructor introduced in C++11

雖然我可以懶惰而且遺漏了最里面的大括號,但是語法糖允許我表明它是那里的initializer_list。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM