5

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. I want to do all those things 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; }

2 Answers 2

8

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<Bar>::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.

Sign up to request clarification or add additional context in comments.

3 Comments

Alternatively, a dummy argument can be used (along the lines of std::nothrow which is of empty type and is only used to select a particular overload)
So, the way I would like it, where the delegate constructor is the generic/templated constructor (and has the same signature as the specific, specialized constructors for Foo and Bar)... That's not possible?
@T.J.Evers 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 sepcify in the specialization, then use the specialization definition in place of the generic one. That is why I have all "three", the generic and the two specializations, constructors call Test(T* t, int i) which handles the code for all cases.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.