调用转换函数后是否调用move构造函数? [英] Is the move constructor called after invoking a conversion function?

查看:88
本文介绍了调用转换函数后是否调用move构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下示例:

struct T { };

struct S {
    operator T();
};

S s;
T t = s;

[dcl.init]将带我们到[over.match.copy],它将找到转换函数operator T().但是我们是在这一点上完成了吗,还是必须通过[dcl.init.ref]调用T(T&& rhs),将rhs绑定到operator T()的返回值?在C ++ 11和C ++ 1z之间,对这个问题的答案是否有任何区别?

[dcl.init] will take us to [over.match.copy] which will find the conversion function operator T(). But are we done at that point, or do we have to invoke T(T&& rhs), binding rhs to the return of operator T() via [dcl.init.ref]? Are there any differences with regards to the answer to this question between C++11 and C++1z?

推荐答案

这属于

This falls under [dcl.init]/17.6.3, which is pretty clear about what happens after overload resolution selects the conversion function:

以初始化器表达式作为其调用的所选函数 争论;如果函数是构造函数,则调用为的prvalue 其结果对象的目标类型的cv不合格版本 由构造函数初始化.通话习惯 根据上述规则,直接初始化是 复制初始化的目的地.

The function selected is called with the initializer expression as its argument; if the function is a constructor, the call is a prvalue of the cv-unqualified version of the destination type whose result object is initialized by the constructor. The call is used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization.

在您的情况下,这又递归为 [dcl.init] /17.6.1 :

In your case this in turn recurses into [dcl.init]/17.6.1:

如果初始值设定项表达式是prvalue且cv不合格 源类型的版本与 目标,初始化器表达式用于初始化 目标对象.

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.


在C ++ 11中,第二步确实调用了一个移动构造函数,因为它没有对应于C ++ 17的17.6.1的项目符号.而是您再次进行直接初始化/重载解析舞蹈:

如果初始化为直接初始化[...],则构造函数为 经过考虑的.适用的构造函数 枚举([over.match.ctor]),然后通过选择最佳的 重载分辨率([over.match]).这样选择的构造函数是 通过初始化器表达式调用,以初始化对象 expression-list作为其参数.如果没有构造函数适用,或者 重载解决方案模棱两可,初始化格式错误.

If the initialization is direct-initialization, [...], constructors are considered. The applicable constructors are enumerated ([over.match.ctor]), and the best one is chosen through overload resolution ([over.match]). The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.

可以(并且实际上)可以避免此举;参见 [class.copy]/31 .

This move can (and in practice will) be elided; see [class.copy]/31.

更有趣的情况是

T t(s);

在C ++ 17措辞下实际上需要来调用move构造函数,因为它使用直接初始化规则,并且对T的构造函数进行重载解析.这将选择T的move构造函数,并调用它来初始化t,将s转换为T prvalue,该prvalue将具体化为临时对象并绑定到move构造函数的参数. 17.6.1项目符号在此过程中根本无法获得,而C ++ 11的[class.copy]/31中的项目符号(现在

which under the C++17 wording is actually required to call a move constructor, because it uses the direct-initialization rule and does overload resolution on T's constructors. That selects T's move constructor and calls it to initialize t, converting s to a T prvalue that is materialized into a temporary and bound to the parameter of the move constructor. The 17.6.1 bullet is simply not reachable in the process, and the bullet in C++11's [class.copy]/31 (now [class.copy.elision]/1) that permitted elision in this scenario was removed in C++17.

这很可能是缺陷.

这篇关于调用转换函数后是否调用move构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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