std::initializer_list和=运算符

3
如果我这样做:
 MyClass a=b;

这里使用复制构造函数来初始化 a,没有涉及到重载的 = 操作符,对吗?
只有在 a 已经被初始化后,再将其分配给其他值时才会使用 = 操作符。
我看到了 this
S(std::initializer_list<T> l) : v(l) {

用法如下:

S<int> s = {1, 2, 3, 4, 5}; // direct list-initialization

这很有趣。它是初始化,并使用了=运算符,但却调用了一个不是复制构造函数的构造函数。为什么它不改为使用以下语法:
S<int> s {1, 2, 3, 4, 5};

那就是使用带有std::initializer_liststd::vector构造函数的方式。当这个运算符不调用复制构造函数时,使用=运算符来初始化对象似乎很令人困惑,不是吗?

Test - Mark Garcia
2个回答

12

这里使用了拷贝构造函数来初始化a,因此没有涉及到等号操作符重载,是吗?

完全正确。

为什么不使用像这样的语法:[...]

两种形式都可以使用,并且它们大部分是等效的,除了使用=的形式被称为复制列表初始化,需要一个非explicit的构造函数(感谢Nicol Bolas的更正)。

另一方面,没有=的形式被称为直接列表初始化,它的工作方式(相当直观)是直接从初始化器构造您的对象(将初始化器作为参数传递给要初始化的对象的构造函数)。构造函数是否是explicit在这里并不相关。

因此,简而言之,这两种形式是等效的,除了复制列表初始化如果您的构造函数是explicit将无法工作。如果不是这种情况,则选择哪种形式大多是一种风格问题。


Explicit - Mark Garcia
我想,既然它将列表传递给构造函数,您还可以将其编写为第三个选项,如 S<int> s({1, 2, 3, 4, 5}); - johnbakers
确实,这在这里得到了证明:http://coliru.stacked-crooked.com/view?id=4b01ae9fdd603fbab6f6667dec3b59ad-50d9cfc8a1d350e7409e81e87c2653ba - johnbakers

4

MyClass a=b;只有在bMyClass类型时才使用复制构造函数。

如果bOtherClass,则需要另一个构造函数,而不是复制构造函数,它需要以OtherClass作为参数(或更可能的是const OtherClass&,但这与问题无关 - 只是防止挑剔者 :)。

你提到的initializer_list也是一样的道理:它是S类型的普通构造函数,接受初始化列表作为参数。从这个意义上说,它与某些假设的构造函数S(int n)没有区别。

想象一下,如果你有:

S(int n) : v(n) {}  // ctor taking an int

您可以像这样创建一个实例:
S s = 4;

同样适用于初始化列表。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接