The following code forwards constructors from base to derived class.
Why 2 copy constructor calls? What happen in the background?
Compiled with g++.
#include <iostream>
using namespace std;
struct A {
A() { cout << "A" << endl; }
A(const A&) { cout << "A(const A&)" << endl; }
template<typename T> A(T a); // Needed to compile :-O
};
template<typename T>
struct C : public T { using T::T; };
int main()
{
A a;
C<A> ca(a);
//C<A> caa(ca);
return 0;
}
Output is:
A
A(const A&)
A(const A&)
You call the function by value and do two copies inside.
No, in C++ you cannot call a constructor from a constructor. What you can do, as warren pointed out, is: Overload the constructor, using different signatures. Use default values on arguments, to make a "simpler" version available.
A copy constructor has as its first parameter a (possibly const or volatile) reference to its own class type. It can have more arguments, but the rest must have default values associated with them.
A copy constructor is a member function that initializes an object using another object of the same class. In simple terms, a constructor which creates an object by initializing it with an object of the same class, which has been created previously is known as a copy constructor.
By defining a constructor template in A
, C
will be given a constructor template with a similar signature. It is implicitly defined similarly to:
template<typename T>
struct C : public T
{
//using T::T;
C() = default;
C(C const&) = default;
template<typename U> C(U a) : T( std::forward<U>(a) ) {}
};
This now calls the copy-constructor of A
twice: once for taking the argument by value. The second call results from T( std::forward<U>(a) )
calling the copy-ctor of A
. This was surprising to me, as you'd expect an inherited ctor to call the exact ctor of the base class of which it has been inherited. But that's not the case, overload resolution selects not the ctor template of A
, but the plain copy-ctor A(A const&)
(see below).
Interestingly, it doesn't care much what the constructor template in A
does, it only needs to be declared. That's why in the OP, the definition can be missing; it can also be deleted (which might be a defect?).
The copy-ctor of A
only has to be chosen during overload resolution of the initialization T( std::forward<U>(a) )
. This is the case here: The argument is an rvalue of type A
, which can bind directly to a const A&
reference, as required by the copy-ctor of A. As the reference binding is direct and w/o derived-to-base conversion, the copy-ctor ranks as an Exact Match. The ctor template in A
is ranked as an Exact Match as well, but as there's a template- and non-template function with the same rank in the overload set, the non-template function is preferred (the copy-ctor A(A const&)
).
One call to A::A(const A&)
is the base class constructor of C<A>
.
The other is called to copy the pass-by-value parameter.
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