调用转换函数后是否调用move构造函数? [英] Is the move constructor called after invoking a conversion function?
问题描述
请考虑以下示例:
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屋!