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
How to Avoid the Diamond of Death When Using Multiple Inheritance
Find Out Whether a C++ Object Is Callable
Vector of Const Objects Giving Compile Error
How to Sort an Stl Map by Value
Check Variadic Templates Parameters for Uniqueness
What Is the Easiest Way to Print a Variadic Parameter Pack Using Std::Ostream
Why Is It Allowed to Pass R-Values by Const Reference But Not by Normal Reference
How to Make C++ Cout Not Use Scientific Notation
Gcc C++ "Hello World" Program -> .Exe Is 500Kb Big When Compiled on Windows. How to Reduce Its Size
C++: Argument Passing "Passed by Reference"
Linker Error When Calling a C Function from C++ Code in Different VS2010 Project
Difference Between Shared Objects (.So), Static Libraries (.A), and Dll's (.So)
Why Does Int*[] Decay into Int** But Not Int[][]
C and C++ Programming on Ubuntu 11.10