是否有任何C ++标准的计划来解决初始化列表构造函数的不一致性?

时间:2018-02-06 05:08:11

标签: c++ c++11 constructor initializer-list c++-standard-library

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大小写与初始化列表构造函数匹配,而string大小写不匹配。这有点难看,常常会造成麻烦。在Scott Meyers的早期章节(第7项)中也注意到了这一点。有效的Modern C ++,他将其描述为标准中有些令人不快的部分,每当初始化列表构造函数可用时,编译器将跳过箍来尝试匹配它,使其优先于每个其他构造函数。

当然,通过将u{3}更改为u(3)可以轻松修复整数情况,但这不是重点。

这是理想的行为吗? C ++标准委员会是否有任何讨论或计划来解决这种模糊/不愉快?一个例子是要求初始化列表构造函数被调用如下:vector<int> u({3}),这已经是合法的。

2 个答案:

答案 0 :(得分:4)

  

C ++标准委员会是否有任何讨论或计划来解决这种歧义/不愉快?

自C ++ 11以来,已有许多初始化修复。例如,您最初无法使用列表初始化(CWG 1467)复制构造聚合。这个非常小的修复程序以一种不合需要的方式破坏了一些代码,如果有initializer_list构造函数(CWG 2137),则导致出现一个新问题来优化之前的修复程序以撤消它。即使在小的情况下,也很难触及这些条款中的任何内容而不会产生许多意外后果和破坏代码。我怀疑将来会有什么样的更改初始化。此时,代码破损的数量将是巨大的。

最好的解决方案是了解初始化的缺陷,并注意你正在做的事情。我的经验法则是当我故意需要{}提供的行为时使用{},否则()

请注意,这与以下更为人熟知的陷阱并无任何不同:

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 ""

即使你要求前者(这是不可能的),你也不能使后者形成错误。

答案 1 :(得分:-7)

首先是一个统一的初始化器,它被引入解决语言歧义。这个问题被称为 Most Vexing Parse 与声明变量有关,由&#34; round&#34; ()括号。 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 AdditionalUserInfo

当然,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。