WalleyM
WalleyM

Reputation: 172

C++ - Overriding Virtual Templated Member Functions

In this example:

class MyClass
{
public:
    MyClass(int i);
};

template<typename T>
class Base
{
public:
    virtual std::unique_ptr<T> createObj()
    {
        return std::make_unique<T>();
    }
};

class Derived  : public Base<MyClass>
{
public:
    std::unique_ptr<MyClass> createObj() override
    {
        return std::make_unique<MyClass>(4);
    }
};

int main() 
{
    Derived instance;
    auto createdObj = instance.createObj();
}

I cannot call the derived createObj() function. It seems the code is trying to still call the base version with the MyClass instance which leads to compilation failures since the required construction arguments are not passed. Why does this not work as a normal overriden function and call the derived version that does supply the correct arguments?

Upvotes: 2

Views: 104

Answers (1)

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122133

You misinterpreted the error. The error message is:

In file included from <source>:1:
In file included from /opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/memory:83:
/opt/compiler-explorer/gcc-10.3.0/lib/gcc/x86_64-linux-gnu/10.3.0/../../../../include/c++/10.3.0/bits/unique_ptr.h:962:34: error: no matching constructor for initialization of 'MyClass'
    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                                 ^
<source>:15:21: note: in instantiation of function template specialization 'std::make_unique<MyClass>' requested here
        return std::make_unique<T>();
                    ^
<source>:19:7: note: in instantiation of member function 'Base<MyClass>::createObj' requested here
class Derived  : public Base<MyClass>
      ^
<source>:6:5: note: candidate constructor not viable: requires single argument 'i', but no arguments were provided
    MyClass(int i);
    ^
<source>:3:7: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided
class MyClass
      ^
<source>:3:7: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 0 were provided
1 error generated.

Base<MyClass> tries to default construct a MyClass but MyClass has no default constuctor. Even if you are not trying to call Base<MyClass>::createObj the method must be valid because it is instantiated as part of Base<MyClass>.

In other words, merely instantiating Base<MyClass> will fail. Not calling the method does not make it less of an error.

I am not entirely sure whats the aim, but if you make the method pure virtual in Base your code compiles without issues:

#include <memory>

class MyClass
{
public:
    MyClass(int i) {}
};

template<typename T>
class Base
{
public:
    virtual std::unique_ptr<T> createObj() = 0;
};

class Derived  : public Base<MyClass>
{
public:
    std::unique_ptr<MyClass> createObj() override
    {
        return std::make_unique<MyClass>(4);
    }
};

int main() 
{
    Derived instance;
    auto createdObj = instance.createObj();
}

Alternatively you could provide a default contructor for MyClass.

Upvotes: 1

Related Questions