Non-const copy constructor compiles fine with C++17

Viewed 193

I'd like to find out why the code below doesn't compile with C++14, but compiles fine with C++17. Any ideas what could be changed since C++17? The thing is of course about non-const copy constructor of a class A. I am using VS 2019. Is this code valid at all?

class A {
public:
    A() { }
    A(A& a) { }
};

A fun() {
    A a;
    return a;
}

int main()
{
    A a = fun();
}

Messages from the compiler:

  1. class A has no suitable copy constructor
  2. initializing cannot convert from A to A
  3. Cannot copy construct class A due to ambiguous copy constructors or no available copy constructor
1 Answers

fun() is a prvalue of type A, so A a = fun(); means that a is the result object of the function call, there is no intermediate temporary.

The text for this is in C++17 [basic.lval]/2:

The result object of a prvalue is the object initialized by the prvalue;

It would be the same for A a = A(A(A(A(A(fun()))))); etc. - all of the prvalues have a as their result object.

The behaviour of the return statement is in [stmt.return]/2:

the return statement initializes the glvalue result or prvalue result object of the (explicit or implicit) function call by copy-initialization (11.6) from the operand.

The result object can be initialized successfully by copy-initialization from a (the local variable of fun) because that is a non-const lvalue and so the copy constructor taking non-const lvalue reference does bind to it.


Prior to C++17 fun()'s return value was a temporary object, and then main's a was copy/move-constructed from the temporary, with elision being optional (but the valid constructor was required to exist).

Related