I’m using a template class with CRTP to implement the clone pattern, with a second template parameter Base to allow for multiple levels of inheritance. I get a compiler error when I try to invoke the indirect base class’s constructor.
class B
{
public:
B() {} //trivial constructor
virtual B* clone()=0;
};
template<class Base, class Derived>
class Clonable
:public Base //weird, I know
{
public:
virtual B* clone() {return new Derived(*this);}
};
class D1 : public Clonable<B, D1>
{
public:
D1(int a); //non-trivial constructor. Different signature than B
};
class D2 : public Clonable<D1, D2>
{
public:
D2(int a): D1(a) {} //compiler error here
}
The only solution I’ve come across so far is to use a variadic template constructor in Cloneable, but my compiler (VC++11) hasn’t implemented them yet.
You need to let your cloning “middleman” class forward constructor arguments, or better (Luc Danton suggested this) use C++11 constructor inheritance.
So, it’s easy to do this in C++11, but it’s not so easy in C++03 or with a current compiler that doesn’t yet support C++11 argument forwarding or constructor inheritance, such as Visual C++10.
One way to do that in C++03, using a helper argument forwarder class, is discussed in my old blog posting “3 ways to mix in a generic cloning implementation”. Then the middleman (cloning implementation) class can look like this:
I discussed the C++03 compatible
ConstructorArgForwarderin earlier blog posting; it can look like this:It in turn uses an argument pack class
ArgPack(well OK, class template), which can look like this:Disclaimer: erors may just have sneaked in e.g. in copying the code from my blog. However, it worked at the time I posted about it, in May 2010.
Note: As I discuss at in the last of the two above blog postings, about cloning, there three main general ways to do it, and of these the simple macro beats the other two with good margin, for C++03. However, with C++11 the “middleman” approach you’ve chosen here seems better. The “sideways inheritance” via dominance is just complicated and inefficient, but if you are restricted to C++03, then do consider a simple macro!
Note 2: The last time I suggested doing the practical & sensible thing, I was heavily downvoted (presumably by Reddit kids). Since then, however, I have stopped caring about SO rep points, and in particular downvotes. So, happily, I can now again give good advice, just like in the old Usenet days, just ignoring them downvoter kids’ mindless reaction to certain words. 🙂