Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling base class template constructor in C++

I have a template base class which has a constructor for conversion from any other template instantiation of that class, like this:

template <class T>
class FooBase
{
public:

    FooBase()
    {
    }

    template <class U>
    FooBase(const FooBase<U>& other)
    {
        std::cout << "FooBase<U>" << std::endl;
    }
};

Notice how there is no copy constructor defined.

I then have a derived template class which does have a copy constructor, as well as the constructor used for conversion:

template <class T>
class Foo : public FooBase<T>
{
public:

    Foo()
    {
    }

    Foo(const Foo& other) :
        FooBase<T>(other)
    {
    }

    template <class U>
    Foo(const Foo<U>& other) :
        FooBase<T>(other)
    {
    }
};

Because FooBase doesn't have a copy constructor, this results in FooBase<T>(other) making a call to the compiler-generated copy constructor. Which means if I run this:

int main()
{
    Foo<int> a;
    Foo<int> b(a);

    return 0;
}

The output is nothing, when it should be FooBase<U>.

Of course, I could try to solve the issue by creating a copy constructor in FooBase and using delegating constructors:

    FooBase(const FooBase& other)
        : FooBase<T>(other)
    {
    }

But unfortunately that doesn't work, and it would result in a recursive call as the compiler helpfully points out:

warning C4717: 'FooBase<int>::FooBase<int>': recursive on all control paths, function will cause runtime stack overflow

So the only solution would be to duplicate the logic into both constructors.

Is there any way around this that doesn't involve code duplication or a separate initialization function?

like image 981
Zeenobit Avatar asked Apr 01 '17 22:04

Zeenobit


People also ask

How do you call a base class constructor?

Whenever the derived class's default constructor is called, the base class's default constructor is called automatically. To call the parameterized constructor of base class inside the parameterized constructor of sub class, we have to mention it explicitly.

Can base class have constructor?

base (C# Reference)A base class access is permitted only in a constructor, an instance method, or an instance property accessor.

Is base class constructor called first?

The compiler knows that when an object of a child class is created, the base class constructor is called first.

What is base constructor?

The constructor of a base class used to instantiate the objects of the base class and the constructor of the derived class used to instantiate the object of the derived class.


1 Answers

You could have a third, private constructor that both the copy constructor and the constructor template delegate to and which contains the actual work:

template <typename T> class FooBase
{
    struct Tag{};

    template <typename U>  // May have U = T
    FooBase(Tag, const FooBase<U> & rhs)
    {
        // actual implementation
    }

public:
    FooBase(const FooBase & rhs) : FooBase(Tag(), rhs) {}

    template <typename U>  // Never selects U = T
    FooBase(const FooBase<U> & rhs) : FooBase(Tag(), rhs) {}
};
like image 174
Kerrek SB Avatar answered Oct 25 '22 08:10

Kerrek SB