Question

I have a template class defined like so:

template <class T>
class Command {
public:
    virtual T HandleSuccess(std::string response) = 0;
    virtual std::string FullCommand() const = 0;
    // ... other methods here ...
};

Will C++ allow me to create a non-template subclass of a template class? What I mean is can I do something like this:

class NoopCommand : public Command<NoopResult> {
public:
    NoopResult HandleSuccess(std::string response);
    std::string FullCommand() const;
    // ... other methods here ...
};

As is that is not working for me because it says the following virtual functions are undefined:

T admix::Command<T>::HandleSuccess(std::string) [with T = admix::NoopResult]
std::string admix::Command<T>::FullCommand() const [with T = admix::NoopResult]

How can I specifically define them for the given T?

Was it helpful?

Solution 5

litb found the solution on ##c++ last night.

The issue was I was passing a NoopCommand to a function like this:

void SendCommand(Command<T> command);

When I should have made the signature this:

void SendCommand(Command<T>& command);

Making that change allows everything to compile.

OTHER TIPS

As we figured out in IRC, that was because you have

  1. Made your functions non-pure
  2. Sliced the derived object part. So the base class functions were called because the object wasn't a complete derived object anymore.

(Below follows my suspicion on earlier versions of your question - i keep it for further consideration and to keep the comments meaningful)


I think the issue here is that the compiler is free to instantiate any virtual function member of a class template even if it's not used (i.e not called). Instantiating a function will need a function definition to be provided. Try to add this in the header, where the compiler will find them and instantiate a definition from:

template<typename T>
T Command<T>::HandleSuccess(std::string response) { /* put some default action ... */ }

template<typename T>
std::string Command<T>::FullCommand() const { /* put some default action ... */ }

C++ Standard 14.7.1/9:

An implementation shall not implicitly instantiate a function template, a member template, a non-virtual member function, a member class or a static data member of a class template that does not require instantiation. It is unspecified whether or not an implementation implicitly instantiates a virtual member function of a class template if the virtual member function would not otherwise be instantiated.

"virtual functions are undefined" means you have not defined the function bodies of NoopCommand::HandleSuccess and NoopCommand::FullCommand.

The following should solve your problem.

class NoopCommand : public Command<NoopResult> {
public:
    NoopResult HandleSuccess(std::string response) {}
    std::string FullCommand() const {}
    // ... other methods here ...
};

Or you you have a NoopCommand.cpp, make sure it's included in your build process.

The pattern you use is widely known as the "Curiously Recurring Template Pattern". so, yes, you can do that.
I can't think of a reason why it does not compile.

The code you gave compiles for me, without errors (after adding a struct NoopResult { };). Maybe there's a problem in the code you left out?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top