在c ++ 17中,struct auto定义的构造函数有哪些规则?

Mor*_*hai 0 c++ struct c++17

鉴于:

struct X {
  int m;
  std::string s;
};
Run Code Online (Sandbox Code Playgroud)

我可以:

X x;  // invokes automatically defined default ctor
X y = { 5 };   // invokes whatever became of the original struct initialization but now maybe runs through C++ initializer-lists?
X z = { 5, "yolo" };  // I assume this is an initializer-list that is being handled by some rule for structs that either runs through a compiler created ctor or copy-from-initializer-list that is similarly compiler-created
Run Code Online (Sandbox Code Playgroud)

乃至...

std::vector<X> vx;
vx.push_back({ 99, "yo" }); // okay
Run Code Online (Sandbox Code Playgroud)

但不是...

vx.emplace_back(99, "yo");  // error VS 2017 v. 15.7.4
vx.emplace_back({99, "yo"});  // error VS 2017 v. 15.7.4
Run Code Online (Sandbox Code Playgroud)

我不理解初始化列表,隐式定义(或编译器定义)ctors和转发函数之间的规则 emplace_back()

有人会非常友好地指出标准的必要部分,或者是一篇关于结构和隐式构造以及其他编译器提供的成员(如copy /)的所有规则的深入讨论的好文章.移动运营商?

我似乎需要一个更全面的规则课 - 因为它似乎emplace_back()应该适用于其中之一emplace_back(int, std::string),或者emplace_back(initializer-list)- 不 - 不是吗?

Bar*_*rry 6

X是一个聚合.虽然聚合的具体定义在每个标准中都有所改变,但您的类型是所有标准中的聚合.

聚合的列表初始化在此处进行聚合初始化.这里没有构造函数 - 没有"auto"构造函数,没有合成构造函数.聚合初始化不会创建构造函数或通过该机制.我们直接从braced-init-list中的相应初始化程序初始化每个类成员.这就是你y和你z正在做的事情.

现在,第二部分.相关部分vector看起来像:

template <typename T>
struct vector {
    void push_back(T&&);

    template <typename... Args>
    void emplace_back(Args&&...);
};
Run Code Online (Sandbox Code Playgroud)

一个支撑,初始化列表,比如{99, "yo"},没有一个类型.而且你不能为它推断出一种类型.它们只能在特定情况下使用.push_back({99, "yo"})工作正常,因为push_backX&&- 它不是一个功能模板 - 我们知道如何进行初始化.

但它emplace_back()是一个函数模板 - 它需要Args...从其参数的类型推断出来.但我们没有类型,没有什么可推断的!这里有一些例外(特别是std::initializer_list<T>可以推断),但在这里,我们被卡住了.你必须写emplace_back(X{99, "yo"})- 这会X在调用方的旁边创建.

同样,emplace_back(99, "yo")因为emplace使用()s来初始化,所以()不起作用,但是你不能 - 初始化聚合.它没有构造函数!