有保证的复制省略如何在C ++ 1z中的列表初始化中工作? [英] How does guaranteed copy elision work in list-initialization in C++1z?

查看:74
本文介绍了有保证的复制省略如何在C ++ 1z中的列表初始化中工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

c ++草稿n4606 [dcl.init] 17.6中有一段有关保证复制保留的段落:

There is a paragraph about guaranteed copy elision in c++ draft n4606 [dcl.init] 17.6:

  • 如果目标类型是(可能是cv限定的)类类型:
    • 如果初始化程序表达式是prvalue,并且源类型的cv不合格版本与目标程序的类相同,则初始化程序表达式将用于初始化目标对象. [示例:T x = T(T(T()));调用T默认构造函数来初始化x. — 示例]
    • [...]
  • If the destination type is a (possibly cv-qualified) class type:
    • If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object. [ Example: T x = T(T(T())); calls the T default constructor to initialize x. — end example ]
    • [...]

还有一个 Q& A 讨论了其工作原理.

There is also a Q&A talks about how it works.

据我所知,我引用的规则保证当初始值设定项表达式为prvalue且源类型的cv不合格版本与目标的类相同时,不应涉及任何ctor.这样就无需检查复制或移动ctor的存在,这使得以下代码在C ++ 17中合法:

To myself understanding, the rule I quoted guarantees that no ctors should get involved when initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination. So that no needs to check the existence of copy or move ctor, which makes following codes to be legal in C++17:

struct A {
    A() {}
    A(A const &) = delete;
    A(A &&) = delete;
};
A f() { return A(); } // it's illegal in C++14, and suppose to be legal in C++17

但是,令我发疯的是我在c ++草案n4606的列表初始化部分中找不到相似的规则.我发现的是([dcl.init.list] 3.6)

However, what drives me crazy is I can't find similar rules in list-initialization section in c++ draft n4606. What I found is ([dcl.init.list] 3.6)

[...]

[...]

  • 否则,如果T是类类型,则考虑构造函数.列举了适用的构造函数,并通过重载决议(13.3、13.3.1.7)选择了最佳的构造函数.如果需要变窄的转换(请参阅下文)以转换任何参数,则程序格式错误. [...]
  • Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution (13.3, 13.3.1.7). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed. [...]

由于列表初始化比我引用的第一个规则具有更高的优先级,因此当初始化程序是initializer-list时,我们应该考虑list-initialized部分中的规则.如我们所见,当列表初始化类类型T时,将考虑构造函数.因此,继续上一个示例,

Since list-initialization has higher priority than the first rule I quoted, we should consider the rule in list-initialized section when the initializer is a initializer-list. As we can see, constructors are considered when list-initialize a class type T. So, continued to the previous example, will

A ff() { return {A()}; }

在C ++ 17中合法吗?有人可以找到标准草稿在哪里指定在列表初始化中保证副本省略的工作方式吗?

be legal in C++17? And can someone find where the standard draft specify how does guaranteed copy elision work in list-initialization?

推荐答案

保证省略的工作方式是重新定义prvalue表达式,以表示将初始化对象".他们不再建造临时工了.临时对象是由prvalue表达式的某些用途构造的.

Guaranteed elision works by redefining prvalue expressions to mean "will initialize an object". They don't construct temporaries anymore; temporaries are instead constructed by certain uses of prvalue expressions.

请注意,经常使用表达"一词.以上.我指出这一点是由于一个非常重要的事实:括号初始化列表不是表达式.标准对此非常清楚.它不是表达式,只有 expressions 可以是prvalues.

Please note the frequent use of the word "expression" above. I point that out because of one very important fact: a braced-init-list is not an expression. The standard is very clear about this. It is not an expression, and only expressions can be prvalues.

实际上,请考虑标准中关于省略的部分:

Indeed, consider the section of the standard on elision:

在以下情况下,允许复制/移动操作的这种省略称为复制删除:

This elision of copy/move operations, called copy elision, is permitted in the following circumstances:

  • 在具有类返回类型的函数中的return语句中,当 expression 是非易失性自动对象的名称时...
  • ...
  • 当尚未绑定到引用(12.2)的临时类对象将被复制/移动到具有相同cv-unqualified类型的类对象时
  • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object...
  • ...
  • when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type

这些都涉及表达式(临时类对象是表达式).大括号初始列表不是表达式.

These all involve expressions (temporary class objects are expressions). Braced-init-lists aren't expressions.

这样,如果发出return {anything};,则无论anything是什么,都不会忽略anything的返回值的构造.根据标准,当然;编译器可能会由于错误而有所不同.

As such, if you issue return {anything};, the construction of the return value from anything will not be elided, regardless of what anything is. According to the standard, of course; compilers may differ due to bugs.

现在,如果您具有与返回值相同类型的prvalue表达式,则极不可能希望键入return {prvalue};而不是仅仅输入return prvalue;.而且,如果表达式是其他类型,则无论如何都不符合省略条件.

Now that being said, if you have a prvalue expression of the same type as the return value, you are highly unlikely to want to type return {prvalue}; instead of just return prvalue;. And if the expression was of a different type, then it doesn't qualify for elision anyway.

这篇关于有保证的复制省略如何在C ++ 1z中的列表初始化中工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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