Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to call a template constructor from a specialized constructor?

Lets say I have this class:

template <class T>
class Test
{
    Test(T* x);

    const T* const t;
    int i{0};
};

I want t to always be initialized with x:

template <class T> Test<T>::Test(T* x) : t{x} {}

And I have two specializations:

template <> Test<Foo>::Test(Foo* x) : t{x} { i = 1; }
template <> Test<Bar>::Test(Bar* x) : t{x} { i = 2; }

Next, I'm extending the class with some other stuff, and that first (templated) constructor does a lot more than just setting t.

All things that I want to do for both T = Foo and T = Bar.

Is there some way that I can call the templated constructor from the specialized constructors?

//This does not work, since it will create a delegation cycle
template <> Test<Foo>::Test(Foo* x) : Test(x) { i = 1; }
template <> Test<Bar>::Test(Bar* x) : Test(x) { i = 2; }
like image 503
T. J. Evers Avatar asked Dec 31 '22 12:12

T. J. Evers


2 Answers

You can use a delegating constructor for this.

You can create a private constructor, that takes the pointer for t, and an int for i. Then you can use that to set x and i, and run all of the shared code.

That would look like:

template <class T>
class Test
{
public:
    Test(T* x) : Test(x, 0) { /*code for default case, runs after delegate*/ }
private:
    Test(T* t, int i) : t(t), i(i) { /*code to run for everything*/ }
    const T* const t;
    int i;
};

template <> Test<Foo>::Test(Foo* x) : Test(x, 1) { /*code only for Foo, runs after delegate*/ }
template <> Test<Foo>::Test(Bar* x) : Test(x, 2) { /*code only for Bar, runs after delegate*/ }

Can the delegate constructor be the generic/templated constructor (with the same signature as the specific, specialized constructors for Foo and Bar)?

No, that isn't possible. When you specialize a function template, you aren't creating a new function, but instead specifying that if T gets deduced to the type you specify in the specialization, then use the specialization definition in place of the generic one.

That is why I have "all three constructors" (the generic and the two specializations) call Test(T* t, int i), which handles the code that is shared by all cases.

like image 186
NathanOliver Avatar answered Jan 18 '23 23:01

NathanOliver


have you thought about inheritance? The first thing that comes to my mind is making a Test class derived from the base class that will have all the things that you wanted the same for both foo and bar took care of. So you could call the base class constructor inside derived class (Test), and then just do things for Foo and bar.

like image 25
Michał Turek Avatar answered Jan 18 '23 22:01

Michał Turek