My understanding about c++ implicit copy constructor is similar to
T(T const& x) :
base1(x), base2(x) ... ,
var1(x.var1), var2(x.var2)...
{}
Move constructor, copy & move assignment also follows similar pattern.
Why was it not defined similar to the following?
T(T const& x) :
base1(static_cast<base1 const&>(x)),
base2(static_cast<base2 const&>(x)) ... ,
var1(x.var1), var2(x.var2)...
{}
Example
I had a class which had implicit copy/move constructor/assignment operator, as well as some converting constructors. I was delegating the job to some implementation class.
class common_work //common implementation of many work like classes
{
common_work(common_work const&) = default;
common_work(common_work&&) = default;// ... implicit constructors work for me.
//a forwarding constructor which can take many work like objects
template<class T, enable_if<work_like<T> > >
common_work(T&& x) { ... }
};
class work1 //one of the implementation
{
work1(work1 const& ) = default;
work1(work1&& ) = default; ...
common_work impl_;
};
This was fine, as work1
copy/move constructors was calling copy/move constructor for common_work
, and forwarding constructor was used by other constructors [not shown in code] which converts from another kind of work
.
Then I thought to inherit work1
from common_work
for EBO and other reasons. So the new work1
class looked like
class work1 : private common_work
{
work1(work1 const& ) = default;
work1(work1&& ) = default; ...
};
But as, work1
is a work_like
class, suddenly the forwarding constructor was getting a better match, as the copy/move constructor for common_work
requires a static_cast
from derived to base.
NOTE :
common_work
as a CRTP , i.e. derived class type passed as template argument, and in forwarding constructor filter it out as enable_if<and_<work_like<T>,not_<is_same<T,Derived> > > >
. Otherwise I have to manually write copy/move constructor/assignment for work1
and static_cast
to base classes explicitly, which is buggy, error prone, and maintenance hazard.This issue was discussed on the MSVC++ bugstracker page some years ago (so if it is not fixed yet, it is a known issue on MSVC++). The Standard says
- ... the base or member is direct-initialized with the corresponding base or member of x.
I did test various compilers when I read the bugreport, and all of them "magically casted". The Standard appears to be quiet on the very details (also about the value category and c/v qualifiers), and just says "with the corresponding base ... of x", which IMO makes much more sense if you take it to mean "with not x, but with the corresponding base ... of x" rather than that you pass it the complete object (I would even go as far as saying that it can only make sense that way).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With