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 的情况匹配初始化列表构造函数,而 string 的情况不匹配。这有点难看,而且经常引起麻烦。在 Scott Meyers 的 Effective Modern C++ 的早期章节(第 7 项)中也提到了这一点,他将其描述为标准中有点令人不快的部分,无论何时初始化列表构造函数可用,编译器都会跳来跳去尝试匹配它,使其优先于所有其他构造函数。

当然,通过将u{3} 更改为u(3) 可以很容易地解决int 大小写问题,但这不是重点。

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

首先是统一初始化器,它被引入是为了解决语言的歧义。这个问题被称为 Most Vexing Parse 与声明变量相关,由 "round" () 括号初始化。 MVP是一种歧义解决,代码类似如下:

class  SomeInitClass;


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

foo这里其实是一个函数的原型,它的参数是一个return是一个Bar的函数,foo函数的return值是一个int。本质上,如果 something 看起来像原型,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++ 语言具有重要意义,它采用隐藏其语法背后的真实值和操作数量的概念。

这不是不一致,至少不是主要的。 vector<string>vector<int> 不相同 class 并且没有相同的构造函数,因为它们不是模板 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。

Has there been any discussion or plans by the C++ standard committee to fix this type of ambiguity / unpleasantness?

自 C++11 以来,对初始化进行了许多修复。例如,您最初无法使用列表初始化 (CWG 1467). This really minor fix broke some code in an undesirable way that lead to a new issue to refine that previous fix to undo it if there's an initializer_list constructor (CWG 2137) 复制构造聚合。在没有很多意想不到的后果和破坏代码的情况下,很难触及这些子句中的任何内容,即使在小情况下也是如此。我怀疑将来是否会推动对初始化进行任何类型的 large 更改。在这一点上,代码破坏的数量将是巨大的。

最好的解决办法就是了解初始化的缺陷并谨慎操作。我的经验法则是仅在我有意需要 {} 提供的行为时才使用 {},否则使用 ()

请注意,这与更广为人知的陷阱并没有什么不同:

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

One example would be requiring initializer list constructors to be called like this: vector<int> u({3}), which is already currently legal.

您遇到了与之前相同的问题,原因相同:

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

即使您需要前者(这是不可能的),您也不能让后者成为病态的。