为什么标准区分直接列表初始化和复制列表初始化? [英] Why does the standard differentiate between direct-list-initialization and copy-list-initialization?

查看:216
本文介绍了为什么标准区分直接列表初始化和复制列表初始化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们知道 T v(x); 被称为直接初始化,而 T v = x; 被称为复制初始化,意味着它将从 x 构造一个临时 T / code>将被复制/移动到 v (这很可能被省略)。

We know that T v(x); is called direct-initialization, while T v = x; is called copy-initialization, meaning that it will construct a temporary T from x that will get copied / moved into v (which is most likely elided).

对于列表初始化,标准区分两种形式,具体取决于上下文。 T v {x}; 被称为直接列表初始化 c $ c>被称为 copy-list-initialization

For list-initialization, the standard differentiates between two forms, depending on the context. T v{x}; is called direct-list-initialization while T v = {x}; is called copy-list-initialization:

§8.5.4[dcl.init.list ] p1


[...]列表初始化可以发生在直接初始化或复制初始化
contexts;在直接初始化上下文中的列表初始化被称为直接列表初始化,并且在复制初始化上下文中的列表初始化被称为复制列表初始化。 [...]

[...] List-initialization can occur in direct-initialization or copy-initialization contexts; list-initialization in a direct-initialization context is called direct-list-initialization and list-initialization in a copy-initialization context is called copy-list-initialization. [...]

但是,在整个标准中只有两个引用。对于直接列表初始化,在创建 T {x} §5.2.3/ 3 )。对于复制列表初始化,它是在 return {x}; §6.6.3/ 2 )。

However, there are only two more references each in the whole standard. For direct-list-initialization, it's mentioned when creating temporaries like T{x} (§5.2.3/3). For copy-list-initialization, it's for the expression in return statements like return {x}; (§6.6.3/2).

现在,以下代码片段如何?

Now, what about the following snippet?

#include <initializer_list>

struct X{
  X(X const&) = delete; // no copy
  X(X&&) = delete; // no move
  X(std::initializer_list<int>){} // only list-init from 'int's
};

int main(){
  X x = {42};
}



通常,从 X x = expr; 模式,我们期望代码无法编译,因为 X 的move构造函数定义为 delete d。但是,最新版本的Clang和GCC编译上面的代码就好了,在挖了一下(找到上面的引号)后,这似乎是正确的行为。标准只定义了整个列表初始化的行为,除了上面提到的点之外,根本不区分两种形式。

Normally, from the X x = expr; pattern, we expect the code to fail to compile, because the move constructor of X is defined as deleted. However, the latest versions of Clang and GCC compile the above code just fine, and after digging a bit (and finding the above quote), that seems to be correct behaviour. The standard only ever defines the behaviour for the whole of list-initialization, and doesn't differentiate between the two forms at all except for the above mentioned points. Well, atleast as far as I can see, anyways.

因此,我再次总结一下我的问题:

So, to summarize my question again:

如果它们(显然)执行完全相同的事情,将列表初始化拆分为两种形式的用途是什么?

推荐答案

因为他们不会做完全相同的事情。如13.3.1.7中所述[over.match.list]:

Because they don't do the exact same thing. As stated in 13.3.1.7 [over.match.list]:


在复制列表初始化中,如果选择显式构造函数,

In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.

简而言之,您只能在复制列表初始化上下文中使用隐式转换。

In short, you can only use implicit conversion in copy-list-initialization contexts.

这是明确添加的,使统一初始化不,um,uniform。

This was explicitly added to make uniform initialization not, um, uniform. Yeah, I know how stupid that sounds, but bear with me.

在2008年, N2640已发布(PDF),查看统一初始化的当前状态。它仔细查看了直接初始化( T {...} )和复制初始化( T = {...} code>)。

In 2008, N2640 was published (PDF), taking a look at the current state of uniform initialization. It looked specifically at the difference between direct initialization (T{...}) and copy-initialization (T = {...}).

总而言之,关注的是显式构造函数会变得毫无意义。如果我有一些类型 T ,我想能够从一个整数构造,但我不想隐式转换,我标记构造函数显式。

To summarize, the concern was that explicit constructors would effectively become pointless. If I have some type T that I want to be able to be constructed from an integer, but I don't want implicit conversion, I label the constructor explicit.

然后有人这样做:

T func()
{
  return {1};
}

没有当前的写法,这将调用我的 explicit 构造函数。那么,如果它不改变太多,使构造函数显式有什么好处呢?

Without the current wording, this will call my explicit constructor. So what good is it to make the constructor explicit if it doesn't change much?

,您需要至少直接使用该名称:

With the current wording, you need to at least use the name directly:

T func()
{
  return T{1};
}

这篇关于为什么标准区分直接列表初始化和复制列表初始化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆