Is the move constructor called after invoking a conversion function?

眉间皱痕 提交于 2019-12-04 22:48:24

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

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.

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

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.


In C++11 the second step does invoke a move constructor, since it doesn't have the bullet corresponding to C++17's 17.6.1. Instead you do the direct-initialization/overload resolution dance again:

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.

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


The more interesting case is actually

T t(s);

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.

This is most likely a defect.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!