Can we return objects having a deleted/private copy/move constructor by value from a function?

In C++03 it is impossible to return an object of a class having a private non-defined copy constructor by value:

struct A { A(int x) { ... } private: A(A const&); };

A f() {
  return A(10); // error!
  return 10;    // error too!
}

I was wondering, was this restriction lifted in C++11, making it possible to write functions having a class type return type for classes without constructors used for copy or move? I remember it could be useful to allow callers of a function use the newly returned object, but that they are not able to copy the value and store it somewhere.


Solution 1:

Here is how it can work

A f() {
  return { 10 };
}

This works even though A has no working copy or move constructor and no other constructor that could copy or move an A!

To make use of this feature of C++11, the constructor (taking int in this case) has to be non-explicit though.

Solution 2:

The restriction has not been lifted. As per the access specifier, there is a note in §12.8/32 that explains:

two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided.

As of the deleted copy/move constructors §8.4.3/2 states that

A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. — end note ]

Not sure about this particular case, but my understanding of the quote is that, if after the overload resolution in §12.8/32 the deleted copy/move constructor is selected, even if the operation is elided, that could constitute a reference to the function, and the program would be ill formed.

Solution 3:

The above code is still ill-formed in C++11. But you could add a public move constructor to A and then it would be legal:

struct A
{
    A(int x) {}
    A(A&&);
private:
    A(A const&);
};

A f() {
  return A(10); // Ok!
}