Re: C++0X explicitly defaulted copy constructors
Marc wrote:
See below for the code. A variadic argument U&&... matches a
copy-from-lvalue better than the implicit copy constructors, so I need
to declare a copy constructor from lvalue. And since its existence
prevents the implicit declaration of the other two versions (from const
ref and from rvalue), I need to declare those 2 as well. Now I don't
want anything fancy for those and I am fine with whatever the compiler
can generate by default, so I default the three copy/move constructors.
Note that you can employ a trick here. Your template will be a better match
than the copy constructor only for U = "A&" and "A const". For that, you can
make the class declaration not declare such a constructor, but introduce it
later on immediately.
struct A {
A()=default;
template<class...U> A(U&&...){
std::cout << "NOOOOO!\n";
}
// note: non-template functions are preferred!
inline A(A&, int); // does not prevent implicit A(A const&);
inline A(A const&&, int); // does not prevent A(A&&);
};
A::A(A&, int = 0) {
/* copy */
}
A::A(A const&&, int = 0) {
/* copy */
}
This is more work than necessary, though, and I haven't tested it.
Note that this way too, your class becomes non-trivial (it's trivial after
the class was defined, but becomes non-trivial after the copy constructors
are defined later on).
You could use SFINAE for this, although I admit it is ugly to catch the
exact case when U... has sizeof...(U) == 1 and such. The following should
suffice, I believe (insert typename as necessary... - and I haven't tested
it)
struct A {
A()=default;
template<class U,
class = enable_if<
!is_same<remove_reference<U>::type const, A const>::value>
::type>
A(U&&) {
std::cout << "YEEEES!\n";
}
template<class...U, class = bool[sizeof...(U) > 1]>
A(U&&...){
std::cout << "YEEEES!\n";
}
};
This way, your class will still be trivially copyable - as opposed to the
out-of-line defaulting workaround.
Note that if issue report http://www.open-
std.org/jtc1/sc22/wg21/docs/cwg_active.html#1080 is rejected, then you don't
need any precautions: A(U&&) will never be used then inplace of a move/copy
constructor. But I doubt it.
The reason GCC rejects your code apparently has something to do with that
the Standard marks first-declaration-explicitly-defaulted functions
potentially trivial (in your case, it actually is trivial). The Standard
requires that such an explicit-defaulting must match the parameter types
that the implicitly-declared copy constructor/move constructor would have.