The initial draft to add the wording for copy deduction was P0620R0, which mentions
This paper is intended to resolve
- The direction on wrapping vs. copying from EWG on Monday in Kona
Some notes on that meeting are available on
https://botondballo.wordpress.com/2017/03/27/trip-report-c-standards-meeting-in-kona-february-2017/:
Copying vs. wrapping behaviour. Suppose a
is a variable of type tuple<int, int>
, and we write tuple b{a};
. Should the type of b
be tuple<int, int>
(the "copying" behaviour), or tuple<tuple<int, int>>
(the "wrapping" behaviour)? This question arises for any wrapper-like type (such as pair
, tuple
, or optional
) which has both a copy constructor and a constructor that takes an object of the type being wrapped. EWG felt copying was the best default. There was some talk of making the behaviour dependent on the syntax of the initialization (e.g. the { }
syntax should always wrap) but EWG felt introducing new inconsistencies between the behaviours of different initialization syntaxes would do more harm than good.
@kiloalphaindia explained this in a comment:
If #2 would use A::A(T)
we would end up with y
beeing A<A<int>>
. [...]
This is right. The A<A<int>>::A(A<int>)
constructor has an exact match in the parameter type. On the other hand, you're also right that A<int>::A(const A<int> &)
would in this case have been preferred instead.
But consider this alternative, where the function equivalent shows that A<A<int>>
would have been preferred if not for the copy deduction candidate:
template <typename T>
struct A {
A(T &&);
A(const A<T> &);
};
template <typename T> auto f(T &&) -> A<T>;
template <typename T> auto f(const A<T> &) -> A<T>;
int main() {
A x1(42); // A<int>
A y1 = std::move(x1); // A<int>
auto x2 = f(42); // A<int>
auto y2 = f(std::move(x2)); // A<A<int>>
}