2

This question is about the wording of the c++ standard.

All compilers, and I think this is what should be, elide the copy constructor for the initialization of the object b bellow (assembly here):

struct B;

struct A{
    operator B();
};

struct B{
    B(const B&);
    B(B&&);
};

void test(A a){
    B b(a);
}

But when I read the standard, I do not see why this elision shall happen (bold mine) [dcl.init]/17.6.2:

Otherwise, 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.

It is specifically said that the constructor is called. But no compiler does it.

I imagine I am missing something or not reading correctly the standard. How should I read the standard?


This contrast with the previous and next paragraphs of the standard that specifically mandate copy elision [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.

and [dlc.init]/17.6.3:

Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversions that can convert from the source type to the destination type [...] The function selected is called with the initializer expression as its argument; [...] The call is used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization.

Where the last sentence send me back to [dcl.init]/17.6.1 which would also implies the copy elision.

Rafael
  • 7,605
  • 13
  • 31
  • 46
Oliv
  • 17,610
  • 1
  • 29
  • 72
  • Seems equivalent to example of [copy_elision](https://en.cppreference.com/w/cpp/language/copy_elision) – Jarod42 Jan 21 '19 at 20:49
  • @Jarod42 I think that all the examples on this page match [dcl.init]/17.6.1 and not the paragraph 17.6.2 that disturbs me. – Oliv Jan 21 '19 at 20:53
  • You're expecting the compiler to convert the `a` object to a temporary `B` object, then copy that temporary object into `b` during the construction of `b`? It uses `b` to store the return value from `a`'s conversion to `B`. – 1201ProgramAlarm Jan 21 '19 at 21:05
  • @1201ProgramAlarm This is what I read in the standard. According to my reading copy-elision should not happen. – Oliv Jan 21 '19 at 21:32
  • If a conversion operator is selected, then the compilers backtrack and process `B b(a)` as if it were `B b(a.operator B());` , and so the prvalue materialization rules (aka. guaranteed copy elision) mean there is only one construction of a `B`. To spell it out, even though the argument `a` is an lvalue, the compilers actually interpret the initialization rules as if it were the prvalue `a.operator B()` in this case. I've previously tried to find supporting evidence for this behaviour in the standard and failed. – M.M Jan 21 '19 at 23:13
  • 3
    https://wg21.link/CWG2327 – T.C. Jan 21 '19 at 23:45

1 Answers1

1

@T.C. answered in a comment, this is core langugage issue CWG2327.

Oliv
  • 17,610
  • 1
  • 29
  • 72