How to Achieve "Virtual Template Function" in C++

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.

Template specialization of pure virtual function

//virtual void func(int a) {} // replace above line with this and it works

Replace the above line and the code compile, doesn't works.

Or, better, works but not as you expect.

The problem is that virtual functions and template functions doesn't mix very well.

So you can't make a template function that directly override a virtual function: if you define func() as a null virtual function

virtual void func(int a) = 0;

the base A class, and all derived classes, become not-instantiable until you don't define an effective virtual func() function.

Defining

virtual void func(int a) {}

the base A class, and all derivate, isn't not-instantiable anymore a you don't need anymore a redefinition of the virtual function.

But the template func() version is not related with virtual function.

When you call b.func(2) in main(), it's the template, not the virtual func() inherited from A, that is called. It's because the template func() "hide" the func() inherited virtual version.

You can "un-hide" the virtual func() version in B adding, in the body of B definition

using A::func;

This way, calling b.func(2); in main(), the virtual version inherited by A is called and the template specialization of func(), so the std::cout <<"hello 2" << std::endl; instruction, ins't executed anymore.

Now... if I understand correctly, you want a template func() function that, in case of T == int join the virtual specialization.

The only way I see is define the virtual override in B

void func (int a) override // override, so necessarily virtual
{ std::cout <<"hello 2" << std::endl; }

and call it from the template specialization

template <>
void B::func<int> (int a)
{ func(a); } // call the virtual override version

The following is a full compiling example

#include <iostream>

struct A
{ virtual void func(int a) = 0; };

struct B : public A
{
void func (int a) override
{ std::cout <<"hello 2" << std::endl; }

template<typename T>
void func (T t)
{ std::cout << "hello" << std::endl; }
};

template <>
void B::func<int> (int a)
{ func(a); }

int main ()
{
B{}.func(2); // call directly virtual func()
B{}.func<int>(2); // call template func() specialization that call virtual func()
}

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.

C++ Override Template class virtual function in Template class

A compiling version of your code:

template <typename data_t, short value_v>
class Base
{
public:
Base() = default; // <== was missing impl, set to default
virtual ~Base() = default; // classes with virtual methods must have virtual destructor
virtual void clear() = 0;

protected:
int variable1;
};

template <typename data_t = short, short value_v = 100>
class Derived :
public Base<data_t, value_v>
{
// by adding a using you can more easily change the template params
// without having to update all your code. Helps keeping code more readable too
using base_t = Base<data_t, value_v>;

public:
void clear() override // <== missing override
{
// different ways of accessing member in template base class
int v1 = Base<data_t, value_v>::variable1;
int v2 = this->variable1;
int v3 = base_t::variable1;
}
};

int main()
{
Derived<short,100> d;
d.clear();
}

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++



Related Topics



Leave a reply



Submit