C++ Virtual Template Method

C++ Virtual template method

The problem is that you cannot mix static time polymorphism (templates) with runtime polymorphism easily. The reason for the language disallowing the particular construct in your example is that there are potentially infinite different types that could be instantiating your template member function, and that in turn means that the compiler would have to generate code to dynamically dispatch those many types, which is infeasible.

There are different things that can be done here to get around the limitation, basically either take away the static or the dynamic polymorphism. Removing dynamic polymorphism from the equation could be done by providing a type that is not derived from, to store the <key,value> mappings, and then offering the template that resolves that only at the base level:

class AbstractComputation {
public:
template <typename T>
void setData( std::string const & id, T value ) {
m_store.setData( id, value );
}
template <typename T>
T getData( std::string const & id ) const {
return m_store.getData<T>( id );
}
protected:
ValueStore m_store;
};

Now deriving classes can access the ValueStore from the base and there is no need for polymorphism. (This can also be done by implementing the functionality directly in AbstractComputation but it probably makes sense to separate concerns)

The other option is to maintain runtime polymorphism, but remove static polymorphism. This can be done by performing type erasure on the base class and then dispatching to the appropriate (non-templated) function that takes the type-erased arguments. The simplest version of this is just using boost::any:

class AbstractComputation {
public:
template <typename T>
void setData( std::string const & id, T value ) {
setDataImpl( id, boost::any( value ) );
}
template <typename T>
T getData( std::string const & id ) const {
boost::any res = getDataImpl( id );
return boost::any_cast<T>( res );
}
protected:
virtual void setDataImpl( std::string const & id, boost::any const & value ) = 0;
virtual boost::any getDataImpl( std::string const & id ) const = 0;
};

How type erasure is implemented under the hood is interesting, but out of the scope here, the important part is that a boost::any is a concrete (non-templated) type that can store any type internally by using type erasure on the arguments, and at the same time allows for type-safe retrieval of the data.

Virtual & Template method C++

You can't create a virtual templated method (yet).

But, if you want the template just so you don't have to have the code everywhere , you can just call the templated method from within the overloaded methods (Code reuse):

template < class T>
void WriteToFileT(T content)
{
streamFile << content;
streamFile << flush;
}

virtual void WriteToFile( double content) //for double
{
WriteToFileT(content);
}

virtual void WriteToFile( int content) //for integer
{
WriteToFileT(content);
}

There are a lot of discussions about this...

Can a C++ class member function template be virtual?

C++ Virtual template method

How to achieve "virtual template function" in C++

Virtual method template in Class template C++

The problem is with F porownywacz, it can't be a template with the pure virtual function.

Virtual member functions can't be templates, to quote clang "virtual cannot be specified on member function templates".

From the cppreference site;

A member function template cannot be virtual, and a member function template in a derived class cannot override a virtual member function from the base class.

The distinction here is essentially ascribed to the virtual functions are a "runtime thing," they are resolved at runtime. The template types are required to be resolved at compile time.

Are you using a conformant complier in the class, what is the teacher using? I would approach you teacher about the issue, quoting the compiler error and to check you are on the same page as your class mates, talk them as well on what error they are getting.


This Q&A contains more detail and some alternatives you may be interested in.

Virtual variadic template method in interface

As much as "prefer composition over inheritance" tends to be parroted blindly, it does comes in handy here.

class LoggerImpl {
public:
virtual ~LoggerImpl() {}
virtual void dispatch(const std::string& message, std::vector<std::string> args) = 0;
};

class Logger {
std::unique_ptr<LoggerImpl> _impl;
public:
Logger(std::unique_ptr<LoggerImpl> impl) : _impl(impl) {}

template<typename... Args>
void Error(const std::string& message, Args... args) const {
std::vector<std::string> args_as_strings;
// Make strings from args

_impl->dispatch(message, std::move(args_as_strings));
}
};

How you actually pass the args to the _impl doesn't have to be a vector. That's mostly an implementation detail. As long as whatever mechanism you use is "virtual-friendly". It'll work fine.



Related Topics



Leave a reply



Submit