在我看来,聚合初始化(合适的类型)不被认为是你可以实际调用的构造函数(除了少数情况.)
例如,如果我们有一个非常简单的聚合类型:
struct Foo {
int x, y;
};
Run Code Online (Sandbox Code Playgroud)
那显然有效:
auto p = new Foo {42, 17}; // not "Foo (42, 17)" though...
Run Code Online (Sandbox Code Playgroud)
但这对我测试的任何编译器都不起作用(包括最新版本的MSVC,GCC和Clang):
std::vector<Foo> v;
v.emplace_back(2, 3);
Run Code Online (Sandbox Code Playgroud)
同样,在我看来,任何想要为类型调用构造函数T的代码(在这种情况下,vector::emplace_back将传递的参数转发给c'tor 的代码T)都不能简单地使用聚合初始化(看起来)因为它们使用括号而不是花括号!
这是为什么?它只是一个遗漏的功能(没有人提出/实施过它),还是有更深层次的原因?这有点奇怪,因为根据定义聚合类型没有其他构造函数来使解决方案模糊不清,因此语言可能刚刚定义了一个默认的聚合构造函数(或者其他东西),它将所有成员都作为默认参数.
这仅仅是语法问题吗?如果vector::emplace_back上面例子中的实现使用new了花括号而不是括号的位置,它会起作用吗?
注意:我要感谢那些已经指出行为的评论vector,emplace因为他们的评论对于那些使用这些关键字找到这个问题的人来说很有价值,但我也想指出那些只是例子.我选择了最熟悉和最简洁的示例,但我的观点是关于在任何代码中显式调用聚合初始值设定项(或placement new更具体地说.)
对于它的价值,P0960"允许从带括号的值列表中初始化聚合"完全符合它的说法.它似乎已经通过EWG并且正在进入C++ 20.
根据定义,聚合类型没有其他构造函数来使解决方案模糊不清
那是不对的.所有类都有默认构造函数,以及复制/移动构造函数.即使你= delete或他们被隐式删除,他们仍然在技术上有这样的构造函数(你只是不能调用它们).
C++是C++,自然存在着极端情况,甚至P0960都会做出"错误的事情",如本文所述:
struct A;
struct C
{
operator A(); //Implicitly convertible to `A`
};
struct A { C c; }; //First member is a `C`
C c2;
A a(c2);
Run Code Online (Sandbox Code Playgroud)
初始化a是一种模糊的情况.可能会发生两件事.您可以执行隐式转换c2为a A,然后a从生成的prvalue 初始化.或者您可以a通过单个值类型执行聚合初始化C.
P0960采用了向后兼容路线:如果一个构造函数可以调用(根据现有规则),那么它的优先级始终.如果没有可以调用的构造函数,则括号仅调用聚合初始化.