Another issue with specialised pure virtual template function (undefined reference) - c++

As a beginner, I have some problem regarding templates, inheritance and pure virtual functions.
Consider the following, where Probability is an abstract template instantiated as RationalProbability.
Probability.h:
template <class T>
class Probability
{
public:
T value;
//Operator overloading for +
virtual Probability<T>* operator+(const Probability<T>& p);
T getValue() const { return value; }
protected:
Probability(T val) {
value = val;
}
~Probability() {};
};
Probability.cpp : empty
RationalProbability.h:
#include "Probability.h"
class RationalProbability: public Probability<float>
{
public:
RationalProbability(float prob);
virtual ~RationalProbability();
RationalProbability* operator+(const RationalProbability& p);
};
RationalProbability.cpp:
#include "RationalProbability.h"
RationalProbability::RationalProbability(float prob): Probability(prob) {}
RationalProbability::~RationalProbability()
{
}
RationalProbability* RationalProbability::operator+(const RationalProbability& p) {
RationalProbability* rp = new RationalProbability(p.getValue() + this->value);
return rp;
}
I get the following error:
Error:undefined reference to
Probability<float>::operator+(Probability<float> const&)
It is true that there is no function with that exact signature, but RationalProbability implements the template exactly with
RationalProbability: public Probability<float>

If you want a base class to have an abstract function (a virtual function you don't implement) you should say so:
virtual Probability<T>* operator+(const Probability<T>& p) = 0;
The = 0 is what tells the compiler that the member function is an abstract method that must be overridden by sub-classes.
If you don't have that, there must be a definition (implementation) of all virtual functions.
If you look closer at the error message it says that it's Probability<float>::operator+ that is missing, not RationalProbability::operator+.
I also suggest you read and check some canonical operator implementations, especially for the binary arithmetic operators, because you should not return a pointer from the operator+ function. It should return an object by value. Otherwise, how would something like a + b + c work if suddenly the result of one addition was a pointer?

Related

Inherited functions to return Derived class, not Base class

Is it possible in C++ to formulate functions in the Base class that return Base type such that in the Derived class, they return Derived type, without overloading?
Minimal example:
class Base
{
public:
Base(double v)
{
value = v;
}
Base add(Base b)
{
return Base(b.value + this->value);
}
void print()
{
std::cout << value << std::endl;
}
double value;
};
class Derived : public Base
{
public:
Derived(double v) : Base(v)
{
}
void timesTwo()
{
value *= 2.0;
}
};
int main()
{
Derived d1(1), d2(2);
// This doesn't work because the result is of type Base
(d1.add(d2)).timesTwo();
return 0;
}
Motivation
In the actual example, Base represents a linear algebra matrix, and Derived represents a vector. The matrix offers many functions that are all applicable to vectors, such as addition or multiplication by a scalar.
In this case, it would be desirable not having to override all these matrix functions manually to return vectors. I would like to, if possible, express that whatever this type is, the return type should be identical to it.
Example:
class Matrix
{
...
Matrix operator*(double x);
};
class Vector : Matrix
{
...
};
Matrix M;
M = M * 2.0; // works
Vector v;
v = v * 2.0; // does not work, because v * 2.0 returns a Matrix
The effort for overriding e.g. operator*() for all derived classes is increased by the fact that there are derived classes for 3- and 2-dimensional vectors, etc.
I understand that a solution is to define a cast from Matrix to Vector (and to Vector3, Vector2, ...) but this would involve copying all entries (which are, for efficiency, stack arrays).
Is there a more efficient solution? And, if not, would it generally be considered cleaner/better to
duplicate all the relevant code in each derived class, or to
define a cast?
In my current understanding, the conflicting problems are:
Duplicate code makes the solution error-prone and more difficult to refactor.
Reusing existing code requires lots of copy operations every time the "scope" changes between Matrix, Vector, Vector3, ... . Would be inefficient if used in large calculations.
Any suggestion would be most appreciated. Thanks!
Yes, but only with free functions (including most operators).
template<class X, class Y,
std::enable_if_t<std::is_base_of<Base, std::decay_t<X>>{},int> =0,
std::enable_if_t<std::is_base_of<Base, std::decay_t<Y>>{},int> =0
>
friend X& operator+=(X&x, Y&& rhs)
{
x.value += rhs.value;
return x.
}
template<class X, class Y,
std::enable_if_t<std::is_base_of<Base, std::decay_t<X>>{},int> =0,
std::enable_if_t<std::is_base_of<Base, std::decay_t<Y>>{},int> =0
>
friend std::decay_t<X> operator+(X&&x, Y&& rhs) {
auto r=std::forward<X>(x);
r+=std::forward<Y>(rhs);
return r;
}
Now if I did that right,
(d1+d2).timesTwo();
works.
I also implemented + in terms of += because that usually works well.
The fancy enable if exists because koenig lookup with very generic template operators causes strange things to happen when you pass Base and types derived from Base to template types and proceed to use + on the resulting type. By saying "only things derived from Base", the right thing happens.
We need to use a template free friend function so we can get the type of "*this" (as it where) within the template to change our return type. This cannot be done in a template member function.
The enable_if clause does not work well in MSVC, but is best practice in other compilers. For MSVC use class=enable_if instead of enable_if=0. The reason why the =0 is best is out of scope here.
Make class Base abstract and put its methods in separated functions. Also declare pure virtual the methods you need in derived classes:
#include <iostream>
class Base
{
public:
Base(double v) : value(v) {}
double value;
virtual void timesTwo() = 0;
};
class Derived : public Base
{
public:
Derived(double v) : Base(v) {}
void timesTwo()
{
value *= 2.0;
std::cout << "timesTwo " << value << std::endl;
}
};
template <class T>
T add(const T& t1, const T& t2)
{
return T(t1.value + t2.value);
}
int main()
{
Derived d1(1), d2(2);
add(d1, d2).timesTwo();
return 0;
}

C++ Virtual Template Class [duplicate]

I have heard that C++ class member function templates can't be virtual. Is this true?
If they can be virtual, what is an example of a scenario in which one would use such a function?
Templates are all about the compiler generating code at compile-time. Virtual functions are all about the run-time system figuring out which function to call at run-time.
Once the run-time system figured out it would need to call a templatized virtual function, compilation is all done and the compiler cannot generate the appropriate instance anymore. Therefore you cannot have virtual member function templates.
However, there are a few powerful and interesting techniques stemming from combining polymorphism and templates, notably so-called type erasure.
From C++ Templates The Complete Guide:
Member function templates cannot be declared virtual. This constraint
is imposed because the usual implementation of the virtual function
call mechanism uses a fixed-size table with one entry per virtual
function. However, the number of instantiations of a member function
template is not fixed until the entire program has been translated.
Hence, supporting virtual member function templates would require
support for a whole new kind of mechanism in C++ compilers and
linkers. In contrast, the ordinary members of class templates can be
virtual because their number is fixed when a class is instantiated
C++ doesn't allow virtual template member functions right now. The most likely reason is the complexity of implementing it. Rajendra gives good reason why it can't be done right now but it could be possible with reasonable changes of the standard. Especially working out how many instantiations of a templated function actually exist and building up the vtable seems difficult if you consider the place of the virtual function call. Standards people just have a lot of other things to do right now and C++1x is a lot of work for the compiler writers as well.
When would you need a templated member function? I once came across such a situation where I tried to refactor a hierarchy with a pure virtual base class. It was a poor style for implementing different strategies. I wanted to change the argument of one of the virtual functions to a numeric type and instead of overloading the member function and override every overload in all sub-classes I tried to use virtual template functions (and had to find out they don't exist.)
Virtual Function Tables
Let's begin with some background on virtual function tables and how they work (source):
[20.3] What's the difference between how virtual and non-virtual
member functions are called?
Non-virtual member functions are resolved statically. That is, the
member function is selected statically (at compile-time) based on the
type of the pointer (or reference) to the object.
In contrast, virtual member functions are resolved dynamically (at
run-time). That is, the member function is selected dynamically (at
run-time) based on the type of the object, not the type of the
pointer/reference to that object. This is called "dynamic binding."
Most compilers use some variant of the following technique: if the
object has one or more virtual functions, the compiler puts a hidden
pointer in the object called a "virtual-pointer" or "v-pointer." This
v-pointer points to a global table called the "virtual-table" or
"v-table."
The compiler creates a v-table for each class that has at least one
virtual function. For example, if class Circle has virtual functions
for draw() and move() and resize(), there would be exactly one v-table
associated with class Circle, even if there were a gazillion Circle
objects, and the v-pointer of each of those Circle objects would point
to the Circle v-table. The v-table itself has pointers to each of the
virtual functions in the class. For example, the Circle v-table would
have three pointers: a pointer to Circle::draw(), a pointer to
Circle::move(), and a pointer to Circle::resize().
During a dispatch of a virtual function, the run-time system follows
the object's v-pointer to the class's v-table, then follows the
appropriate slot in the v-table to the method code.
The space-cost overhead of the above technique is nominal: an extra
pointer per object (but only for objects that will need to do dynamic
binding), plus an extra pointer per method (but only for virtual
methods). The time-cost overhead is also fairly nominal: compared to a
normal function call, a virtual function call requires two extra
fetches (one to get the value of the v-pointer, a second to get the
address of the method). None of this runtime activity happens with
non-virtual functions, since the compiler resolves non-virtual
functions exclusively at compile-time based on the type of the
pointer.
My problem, or how I came here
I'm attempting to use something like this now for a cubefile base class with templated optimized load functions which will be implemented differently for different types of cubes (some stored by pixel, some by image, etc).
Some code:
virtual void LoadCube(UtpBipCube<float> &Cube,long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<unsigned short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
What I'd like it to be, but it won't compile due to a virtual templated combo:
template<class T>
virtual void LoadCube(UtpBipCube<T> &Cube,long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
I ended up moving the template declaration to the class level. This solution would have forced programs to know about specific types of data they would read before they read them, which is unacceptable.
Solution
warning, this isn't very pretty but it allowed me to remove repetitive execution code
1) in the base class
virtual void LoadCube(UtpBipCube<float> &Cube,long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<unsigned short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
2) and in the child classes
void LoadCube(UtpBipCube<float> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1)
{ LoadAnyCube(Cube,LowerLeftRow,LowerLeftColumn,UpperRightRow,UpperRightColumn,LowerBand,UpperBand); }
void LoadCube(UtpBipCube<short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1)
{ LoadAnyCube(Cube,LowerLeftRow,LowerLeftColumn,UpperRightRow,UpperRightColumn,LowerBand,UpperBand); }
void LoadCube(UtpBipCube<unsigned short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1)
{ LoadAnyCube(Cube,LowerLeftRow,LowerLeftColumn,UpperRightRow,UpperRightColumn,LowerBand,UpperBand); }
template<class T>
void LoadAnyCube(UtpBipCube<T> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1);
Note that LoadAnyCube is not declared in the base class.
Here's another stack overflow answer with a work around:
need a virtual template member workaround.
The following code can be compiled and runs properly, using MinGW G++ 3.4.5 on Window 7:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class A{
public:
virtual void func1(const T& p)
{
cout<<"A:"<<p<<endl;
}
};
template <typename T>
class B
: public A<T>
{
public:
virtual void func1(const T& p)
{
cout<<"A<--B:"<<p<<endl;
}
};
int main(int argc, char** argv)
{
A<string> a;
B<int> b;
B<string> c;
A<string>* p = &a;
p->func1("A<string> a");
p = dynamic_cast<A<string>*>(&c);
p->func1("B<string> c");
B<int>* q = &b;
q->func1(3);
}
and the output is:
A:A<string> a
A<--B:B<string> c
A<--B:3
And later I added a new class X:
class X
{
public:
template <typename T>
virtual void func2(const T& p)
{
cout<<"C:"<<p<<endl;
}
};
When I tried to use class X in main() like this:
X x;
x.func2<string>("X x");
g++ report the following error:
vtempl.cpp:34: error: invalid use of `virtual' in template declaration of `virtu
al void X::func2(const T&)'
So it is obvious that:
virtual member function can be used in a class template. It is easy for compiler to construct vtable
It is impossible to define a class template member function as virtual, as you can see, it hard to determine function signature and allocate vtable entries.
No they can't. But:
template<typename T>
class Foo {
public:
template<typename P>
void f(const P& p) {
((T*)this)->f<P>(p);
}
};
class Bar : public Foo<Bar> {
public:
template<typename P>
void f(const P& p) {
std::cout << p << std::endl;
}
};
int main() {
Bar bar;
Bar *pbar = &bar;
pbar -> f(1);
Foo<Bar> *pfoo = &bar;
pfoo -> f(1);
};
has much the same effect if all you want to do is have a common interface and defer implementation to subclasses.
No, template member functions cannot be virtual.
In the other answers the proposed template function is a facade and doesn't offer any practical benefit.
Template functions are useful for writing code only once using
different types.
Virtual functions are useful for having a common interface for different classes.
The language doesn't allow virtual template functions but with a workaround it is possible to have both, e.g. one template implementation for each class and a virtual common interface.
It is however necessary to define for each template type combination a dummy virtual wrapper function:
#include <memory>
#include <iostream>
#include <iomanip>
//---------------------------------------------
// Abstract class with virtual functions
class Geometry {
public:
virtual void getArea(float &area) = 0;
virtual void getArea(long double &area) = 0;
};
//---------------------------------------------
// Square
class Square : public Geometry {
public:
float size {1};
// virtual wrapper functions call template function for square
virtual void getArea(float &area) { getAreaT(area); }
virtual void getArea(long double &area) { getAreaT(area); }
private:
// Template function for squares
template <typename T>
void getAreaT(T &area) {
area = static_cast<T>(size * size);
}
};
//---------------------------------------------
// Circle
class Circle : public Geometry {
public:
float radius {1};
// virtual wrapper functions call template function for circle
virtual void getArea(float &area) { getAreaT(area); }
virtual void getArea(long double &area) { getAreaT(area); }
private:
// Template function for Circles
template <typename T>
void getAreaT(T &area) {
area = static_cast<T>(radius * radius * 3.1415926535897932385L);
}
};
//---------------------------------------------
// Main
int main()
{
// get area of square using template based function T=float
std::unique_ptr<Geometry> geometry = std::make_unique<Square>();
float areaSquare;
geometry->getArea(areaSquare);
// get area of circle using template based function T=long double
geometry = std::make_unique<Circle>();
long double areaCircle;
geometry->getArea(areaCircle);
std::cout << std::setprecision(20) << "Square area is " << areaSquare << ", Circle area is " << areaCircle << std::endl;
return 0;
}
Output:
Square area is 1, Circle area is 3.1415926535897932385
Try it here
To answer the second part of the question:
If they can be virtual, what is an example of a scenario in which one would use such a function?
This is not an unreasonable thing to want to do. For instance, Java (where every method is virtual) has no problems with generic methods.
One example in C++ of wanting a virtual function template is a member function that accepts a generic iterator. Or a member function that accepts a generic function object.
The solution to this problem is to use type erasure with boost::any_range and boost::function, which will allow you to accept a generic iterator or functor without the need to make your function a template.
While an older question that has been answered by many I believe a succinct method, not so different from the others posted, is to use a minor macro to help ease the duplication of class declarations.
// abstract.h
// Simply define the types that each concrete class will use
#define IMPL_RENDER() \
void render(int a, char *b) override { render_internal<char>(a, b); } \
void render(int a, short *b) override { render_internal<short>(a, b); } \
// ...
class Renderable
{
public:
// Then, once for each on the abstract
virtual void render(int a, char *a) = 0;
virtual void render(int a, short *b) = 0;
// ...
};
So now, to implement our subclass:
class Box : public Renderable
{
public:
IMPL_RENDER() // Builds the functions we want
private:
template<typename T>
void render_internal(int a, T *b); // One spot for our logic
};
The benefit here is that, when adding a newly supported type, it can all be done from the abstract header and forego possibly rectifying it in multiple source/header files.
There is a workaround for 'virtual template method' if set of types for the template method is known in advance.
To show the idea, in the example below only two types are used (int and double).
There, a 'virtual' template method (Base::Method) calls corresponding virtual method (one of Base::VMethod) which, in turn, calls template method implementation (Impl::TMethod).
One only needs to implement template method TMethod in derived implementations (AImpl, BImpl) and use Derived<*Impl>.
class Base
{
public:
virtual ~Base()
{
}
template <typename T>
T Method(T t)
{
return VMethod(t);
}
private:
virtual int VMethod(int t) = 0;
virtual double VMethod(double t) = 0;
};
template <class Impl>
class Derived : public Impl
{
public:
template <class... TArgs>
Derived(TArgs&&... args)
: Impl(std::forward<TArgs>(args)...)
{
}
private:
int VMethod(int t) final
{
return Impl::TMethod(t);
}
double VMethod(double t) final
{
return Impl::TMethod(t);
}
};
class AImpl : public Base
{
protected:
AImpl(int p)
: i(p)
{
}
template <typename T>
T TMethod(T t)
{
return t - i;
}
private:
int i;
};
using A = Derived<AImpl>;
class BImpl : public Base
{
protected:
BImpl(int p)
: i(p)
{
}
template <typename T>
T TMethod(T t)
{
return t + i;
}
private:
int i;
};
using B = Derived<BImpl>;
int main(int argc, const char* argv[])
{
A a(1);
B b(1);
Base* base = nullptr;
base = &a;
std::cout << base->Method(1) << std::endl;
std::cout << base->Method(2.0) << std::endl;
base = &b;
std::cout << base->Method(1) << std::endl;
std::cout << base->Method(2.0) << std::endl;
}
Output:
0
1
2
3
NB:
Base::Method is actually surplus for real code (VMethod can be made public and used directly).
I added it so it looks like as an actual 'virtual' template method.
At least with gcc 5.4 virtual functions could be template members but has to be templates themselves.
#include <iostream>
#include <string>
class first {
protected:
virtual std::string a1() { return "a1"; }
virtual std::string mixt() { return a1(); }
};
class last {
protected:
virtual std::string a2() { return "a2"; }
};
template<class T> class mix: first , T {
public:
virtual std::string mixt() override;
};
template<class T> std::string mix<T>::mixt() {
return a1()+" before "+T::a2();
}
class mix2: public mix<last> {
virtual std::string a1() override { return "mix"; }
};
int main() {
std::cout << mix2().mixt();
return 0;
}
Outputs
mix before a2
Process finished with exit code 0
My current solution is the following (with RTTI disabled - you could use std::type_index, too):
#include <type_traits>
#include <iostream>
#include <tuple>
class Type
{
};
template<typename T>
class TypeImpl : public Type
{
};
template<typename T>
inline Type* typeOf() {
static Type* typePtr = new TypeImpl<T>();
return typePtr;
}
/* ------------- */
template<
typename Calling
, typename Result = void
, typename From
, typename Action
>
inline Result DoComplexDispatch(From* from, Action&& action);
template<typename Cls>
class ChildClasses
{
public:
using type = std::tuple<>;
};
template<typename... Childs>
class ChildClassesHelper
{
public:
using type = std::tuple<Childs...>;
};
//--------------------------
class A;
class B;
class C;
class D;
template<>
class ChildClasses<A> : public ChildClassesHelper<B, C, D> {};
template<>
class ChildClasses<B> : public ChildClassesHelper<C, D> {};
template<>
class ChildClasses<C> : public ChildClassesHelper<D> {};
//-------------------------------------------
class A
{
public:
virtual Type* GetType()
{
return typeOf<A>();
}
template<
typename T,
bool checkType = true
>
/*virtual*/void DoVirtualGeneric()
{
if constexpr (checkType)
{
return DoComplexDispatch<A>(this, [&](auto* other) -> decltype(auto)
{
return other->template DoVirtualGeneric<T, false>();
});
}
std::cout << "A";
}
};
class B : public A
{
public:
virtual Type* GetType()
{
return typeOf<B>();
}
template<
typename T,
bool checkType = true
>
/*virtual*/void DoVirtualGeneric() /*override*/
{
if constexpr (checkType)
{
return DoComplexDispatch<B>(this, [&](auto* other) -> decltype(auto)
{
other->template DoVirtualGeneric<T, false>();
});
}
std::cout << "B";
}
};
class C : public B
{
public:
virtual Type* GetType() {
return typeOf<C>();
}
template<
typename T,
bool checkType = true
>
/*virtual*/void DoVirtualGeneric() /*override*/
{
if constexpr (checkType)
{
return DoComplexDispatch<C>(this, [&](auto* other) -> decltype(auto)
{
other->template DoVirtualGeneric<T, false>();
});
}
std::cout << "C";
}
};
class D : public C
{
public:
virtual Type* GetType() {
return typeOf<D>();
}
};
int main()
{
A* a = new A();
a->DoVirtualGeneric<int>();
}
// --------------------------
template<typename Tuple>
class RestTuple {};
template<
template<typename...> typename Tuple,
typename First,
typename... Rest
>
class RestTuple<Tuple<First, Rest...>> {
public:
using type = Tuple<Rest...>;
};
// -------------
template<
typename CandidatesTuple
, typename Result
, typename From
, typename Action
>
inline constexpr Result DoComplexDispatchInternal(From* from, Action&& action, Type* fromType)
{
using FirstCandidate = std::tuple_element_t<0, CandidatesTuple>;
if constexpr (std::tuple_size_v<CandidatesTuple> == 1)
{
return action(static_cast<FirstCandidate*>(from));
}
else {
if (fromType == typeOf<FirstCandidate>())
{
return action(static_cast<FirstCandidate*>(from));
}
else {
return DoComplexDispatchInternal<typename RestTuple<CandidatesTuple>::type, Result>(
from, action, fromType
);
}
}
}
template<
typename Calling
, typename Result
, typename From
, typename Action
>
inline Result DoComplexDispatch(From* from, Action&& action)
{
using ChildsOfCalling = typename ChildClasses<Calling>::type;
if constexpr (std::tuple_size_v<ChildsOfCalling> == 0)
{
return action(static_cast<Calling*>(from));
}
else {
auto fromType = from->GetType();
using Candidates = decltype(std::tuple_cat(std::declval<std::tuple<Calling>>(), std::declval<ChildsOfCalling>()));
return DoComplexDispatchInternal<Candidates, Result>(
from, std::forward<Action>(action), fromType
);
}
}
The only thing I don't like is that you have to define/register all child classes.
I have looked at all the 14 answers, Some have reasons why virtual templates functions can't work, others show a work around. One answer even showed that virtual classes can have virtual functions. Which shouldn't be too surprising.
My answer will give a straight up reason why the standard doesn't allow virtual templated functions. Since so many have been complaining. Firstly though, I can't believe that some people have commented that virtual functions can be deduced at compile time. That is the dumbest thing I ever heard.
Anyhow. I am certain that the standard dictates that a this pointer to the object is the first argument to its member function.
struct MyClass
{
void myFunction();
}
// translate to
void myFunction(MyClass*);
Now that we are clear on this. We then need to know the conversion rules for templates. A templated parameter is extremely limited to what it can implicitly convert to. I don't remember all of it, but you can check C++ Primer for complete reference. For example T* is convertible to const T*. Arrays are convertible to pointers. However, derived class is not convertible to base class as a templated parameter.
struct A {};
struct B : A {};
template<class T>
void myFunction(T&);
template<>
void myFunction<A>(A&) {}
int main()
{
A a;
B b;
myFunction(a); //compiles perfectly
myFunction((A&)b); // compiles nicely
myFunction(b); //compiler error, use of undefined template function
}
So I hope you see where I am getting at. You cannot have a virtual template function because as far as the compiler is concerned they are two completedly different functions; as their implicit this parameter is of different type.
Another reasons why virtual templates can't work are equally valid. Since virtual tables are the best way to implement virtual functions fast.
How right function is called in case of virtual?
Vtable will contain entries for each virtual function of class and at run time it will pick the address of specific function and it will call respective function.
How right function has to be called in case of virtual along with function template?
In case of function template, user can call this function with any type. Here same function has several versions based on type. Now, in this case for same function because of different versions, many entries in vtable has to be maintained.

C++ - undefined reference to Base class operator

I have a template base class Vect, from which VectDynamic is derived.
Base class (Vect.h):
template <typename Elem>
class Vect
{
public:
virtual Elem& operator[](std::ptrdiff_t);
};
Derived class (VectDynamic.h):
#include "Vect.h"
template <typename Elem>
class VectDynamic: public Vect<Elem>
{
std::size_t _dim;
Elem* _val;
public:
explicit VectDynamic(std::size_t dim = 0): _dim(dim), _val(new Elem[dim]) {}
VectDynamic(std::size_t, const Elem&);
VectDynamic(const VectDynamic&);
Elem& operator[](std::ptrdiff_t) override;
};
template <typename Elem>
VectDynamic<Elem>::VectDynamic(std::size_t size, const Elem& e):
_dim(size), _val(new Elem[size])
{
for (std::size_t i = 0; i < size; ++i) _val[i] = e;
}
template <typename Elem>
VectDynamic<Elem>::VectDynamic(const VectDynamic& v):
_dim(v._dim), _val(new Elem[v._dim])
{
for (std::size_t i = 0; i < v._dim; ++i) _val[i] = v._val[i];
}
template <typename Elem>
Elem& VectDynamic<Elem>::operator[] (std::ptrdiff_t i)
{
if (std::size_t(i) >= _dim)
throw std::out_of_range("VectDynamic : Index out of range");
return _val[i];
}
When I try to create an instance of the derived class like this (main.cpp):
#include "VectDynamic.h"
int main()
{
VectDynamic<double> v1(5, 2);
return 0;
}
I end up having this error from both classes:
undefined reference to 'VectDynamic<double>::operator[](long)'
Now I know many posts talk about this kind of error, but after hours of searching I couldn't find any reason why it would happen in my case.
I don't think the error would come from the way I includes the files, as it doesn't work either when everything is in a single file.
I've read in this post that it might be due to the the implicit instantiation of the base class that goes on when the derived class is declared since the base class's methods aren't defined yet.
Do you think that is the problem ?
What would be a decent workaround ?
EDIT: Forgot to add the operator[] from the child, added it now (it wasn't causing any error as it was in my code).
Even though Vect<double>::operator[] will never get called, the base vtable must be used for a moment during construction of the derived object and as you declared things, the base vtable has a pointer to that undefined method. That should be solved by adding "=0" (commonly described as "pure virtual") to the declaration of the base method.
Change to
template <typename Elem>
class Vect
{
public:
virtual Elem& operator[](std::ptrdiff_t)=0;
};
From the error it seems pretty clear that you just didn't define VectDynamic<double>::operator[]. If you don't want the [] operator just remove the function declarations. If you do want it, you'll need to implement it.
Note that since it's a template class you can't implement the operator in a non-header source file.
And now that I've said all that, let me just also point out since you don't (correctly) follow the rule of 0, 3, or 5 you'll be leaking memory; is there a reason you aren't using std::vector?

How can I force a compiler error if an un-overridden virtual method is called?

This is a rather general question about style and safety when writing a template base class in C++. Bear with me, though, there is a specific question at the end...
I have a template base class which fully implements the required functionality when the type T is a primitive type (int, float, etc.). However,if T is not primitive (for example, if T is a class that needs to have a constructor called with a specific set of arguments) then some of the methods will need to be overridden, and for this reason they are declared virtual in the template. The template also contains a pure virtual method which forces it to be abstract, so in order to be used it must be derived from: a derived class based on a primitive type can use all the methods as provided and override just the pure virtual one, whilst a derived class based on a non-primitive type should override all the virtual methods.
For example:
template <typename T> class myTemplate
{
public:
// Constructor:
myTemplate<T>();
// Destructor:
virtual ~myTemplate();
// General function, valid for all classes derived from this:
void printMe()
{
printf("Hello, I'm from the template\r\n");
}
// Primitive function, must be overridden for non-primitive types:
virtual T DoSomething(const T& myClass)
{
T result = result + static_cast<T>(1);
return result;
}
// Primitive function, must be overridden for non-primitive types:
virtual T DoSomethingElse(const T& myClass)
{
T result = result - static_cast<T>(1);
return result;
}
// Pure Virtual function, must be overridden in all cases:
virtual void RefrainFromDoingAnythingAtAll(const T& myClass) = 0
};
class myIntegerClass : public myTemplate<int>
{
public:
virtual void RefrainFromDoingAnythingAtAll(const int& myInteger) {}
};
Suppose now I want to create a derived class where I expect 'DoSomething' to be called, but can't envisage any circumstances under which 'DoSomethingElse' would be useful. Therefore I'd like to reimplement 'DoSomething', but not bother with 'DoSomethingElse'. Nevertheless, if at some point the derived class's 'DoSomethingElse' method does get called (either because I really meant to call 'DoSomething' but wrote the wrong thing by mistake, or because a circumstance arose which I had earlier failed to envisage), then I want a compiler warning to be issued to remind me that I can't do this unless I reimplement 'DoSomethingElse' first.
For example:
class myWatermelonClass : public myTemplate<Watermelon>
{
public:
virtual Watermelon DoSomething(const Watermelon &myWatermelon)
{
// Just return a copy of the original:
Watermelon anotherWatermelon(myWatermelon);
return anotherWatermelon;
}
virtual Watermelon DoSomethingElse(const Watermelon &myWatermelon)
{
// This routine shouldn't ever get called: if it does, then
// either I've made an error or, if I find that I really need
// to reimplement it after all, then I'd better buckle down
// and do it.
< How do I make the compiler remind me of this? >
}
virtual void RefrainFromDoingAnythingAtAll(const Watermelon& myWatermelon) {}
};
Obviously I know about the standard #error and #warning compiler directives, but if I use one of these then the error (or warning) is flagged every time I compile. What I want is to make sure that an error is given at compile time if I negligently call
DoSomethingElse(aSpecificWatermelon);
from somewhere in my code, but not otherwise. Is there a way to achieve this? Or is this just a fundamentally bad design in the first place?
I think you are misusing templates and virtual dispatch mix. For instance, you base class is not going to compile for any type that does not support addition operator and being constructible from an int. Every time myTemplate gets specialised implicitly, all the virtual functions will be compiled, even if you override them in derived classes:
virtual T DoSomething(const T& myClass)
{
T result = result + static_cast<T>(1); // compile error when T == Watermelon
return result;
}
In you case, what you are looking for is the explicit template specialisation:
template <>
class myTemplate<Watermelon>
{
public:
// General function, valid for all classes derived from this:
void printMe()
{
printf("Hello, I'm from the Watermelon template specialisation\r\n");
}
virtual Watermelon DoSomething(const Watermelon &myWatermelon)
{
// Just return a copy of the original:
Watermelon anotherWatermelon(myWatermelon);
return anotherWatermelon;
}
// notice there's no DoSomethingElse!
virtual void RefrainFromDoingAnythingAtAll(const Watermelon& myWatermelon) {}
};
Now calling DoSomethingElse on an instance of myTemplate<Watermelon> will immediately give you a compile error, since there's no such function.
By using static_assert, you can cause a compile error when you try to call a function that doesn't meet certain criteria. There is no need for virtual functions at all. Here is an example:
#include <iostream>
#include <type_traits>
using std::cout;
template <typename T>
struct myTemplate {
void printMe() { cout << "Hello, I'm from the template\r\n"; }
T DoSomething(const T& myClass)
{
static_assert(
std::is_fundamental<T>::value,
"DoSomething must be redefined in derived classes "
"for non-fundamental types."
);
T result = myClass + static_cast<T>(1);
return result;
}
T DoSomethingElse(const T& myClass)
{
static_assert(
std::is_fundamental<T>::value,
"DoSomethingElse must be redefined in derived classes "
"for non-fundamental types."
);
T result = myClass - static_cast<T>(1);
return result;
}
template <typename U>
struct never_true { static const bool value = false; };
void RefrainFromDoingAnythingAtAll(const T&)
{
static_assert(
never_true<T>::value,
"RefrainFromDoingAnythingAtAll must be redefined "
"in derived classes."
);
}
};
struct Watermelon {
};
struct Lemon {
};
struct myIntegerClass : myTemplate<int> {
void RefrainFromDoingAnythingAtAll(const int &) { }
};
struct myWatermelonClass : myTemplate<Watermelon> {
Watermelon DoSomething(const Watermelon&)
{
return Watermelon();
}
Watermelon DoSomethingElse(const Watermelon&)
{
return Watermelon();
}
void RefrainFromDoingAnythingAtAll(const Watermelon &) { }
};
struct myLemonClass : myTemplate<Lemon> {
};
int main()
{
myIntegerClass x;
x.DoSomething(5); // works
x.DoSomethingElse(5); // works
x.RefrainFromDoingAnythingAtAll(5); // works
myWatermelonClass y;
y.DoSomething(Watermelon()); // works
y.DoSomethingElse(Watermelon()); // works
y.RefrainFromDoingAnythingAtAll(Watermelon()); // works
myLemonClass z;
z.DoSomething(Lemon()); // error
z.DoSomethingElse(Lemon()); // error
z.RefrainFromDoingAnythingAtAll(Lemon()); // error
}

Templated virtual member functions [duplicate]

I have heard that C++ class member function templates can't be virtual. Is this true?
If they can be virtual, what is an example of a scenario in which one would use such a function?
Templates are all about the compiler generating code at compile-time. Virtual functions are all about the run-time system figuring out which function to call at run-time.
Once the run-time system figured out it would need to call a templatized virtual function, compilation is all done and the compiler cannot generate the appropriate instance anymore. Therefore you cannot have virtual member function templates.
However, there are a few powerful and interesting techniques stemming from combining polymorphism and templates, notably so-called type erasure.
From C++ Templates The Complete Guide:
Member function templates cannot be declared virtual. This constraint
is imposed because the usual implementation of the virtual function
call mechanism uses a fixed-size table with one entry per virtual
function. However, the number of instantiations of a member function
template is not fixed until the entire program has been translated.
Hence, supporting virtual member function templates would require
support for a whole new kind of mechanism in C++ compilers and
linkers. In contrast, the ordinary members of class templates can be
virtual because their number is fixed when a class is instantiated
C++ doesn't allow virtual template member functions right now. The most likely reason is the complexity of implementing it. Rajendra gives good reason why it can't be done right now but it could be possible with reasonable changes of the standard. Especially working out how many instantiations of a templated function actually exist and building up the vtable seems difficult if you consider the place of the virtual function call. Standards people just have a lot of other things to do right now and C++1x is a lot of work for the compiler writers as well.
When would you need a templated member function? I once came across such a situation where I tried to refactor a hierarchy with a pure virtual base class. It was a poor style for implementing different strategies. I wanted to change the argument of one of the virtual functions to a numeric type and instead of overloading the member function and override every overload in all sub-classes I tried to use virtual template functions (and had to find out they don't exist.)
Virtual Function Tables
Let's begin with some background on virtual function tables and how they work (source):
[20.3] What's the difference between how virtual and non-virtual
member functions are called?
Non-virtual member functions are resolved statically. That is, the
member function is selected statically (at compile-time) based on the
type of the pointer (or reference) to the object.
In contrast, virtual member functions are resolved dynamically (at
run-time). That is, the member function is selected dynamically (at
run-time) based on the type of the object, not the type of the
pointer/reference to that object. This is called "dynamic binding."
Most compilers use some variant of the following technique: if the
object has one or more virtual functions, the compiler puts a hidden
pointer in the object called a "virtual-pointer" or "v-pointer." This
v-pointer points to a global table called the "virtual-table" or
"v-table."
The compiler creates a v-table for each class that has at least one
virtual function. For example, if class Circle has virtual functions
for draw() and move() and resize(), there would be exactly one v-table
associated with class Circle, even if there were a gazillion Circle
objects, and the v-pointer of each of those Circle objects would point
to the Circle v-table. The v-table itself has pointers to each of the
virtual functions in the class. For example, the Circle v-table would
have three pointers: a pointer to Circle::draw(), a pointer to
Circle::move(), and a pointer to Circle::resize().
During a dispatch of a virtual function, the run-time system follows
the object's v-pointer to the class's v-table, then follows the
appropriate slot in the v-table to the method code.
The space-cost overhead of the above technique is nominal: an extra
pointer per object (but only for objects that will need to do dynamic
binding), plus an extra pointer per method (but only for virtual
methods). The time-cost overhead is also fairly nominal: compared to a
normal function call, a virtual function call requires two extra
fetches (one to get the value of the v-pointer, a second to get the
address of the method). None of this runtime activity happens with
non-virtual functions, since the compiler resolves non-virtual
functions exclusively at compile-time based on the type of the
pointer.
My problem, or how I came here
I'm attempting to use something like this now for a cubefile base class with templated optimized load functions which will be implemented differently for different types of cubes (some stored by pixel, some by image, etc).
Some code:
virtual void LoadCube(UtpBipCube<float> &Cube,long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<unsigned short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
What I'd like it to be, but it won't compile due to a virtual templated combo:
template<class T>
virtual void LoadCube(UtpBipCube<T> &Cube,long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
I ended up moving the template declaration to the class level. This solution would have forced programs to know about specific types of data they would read before they read them, which is unacceptable.
Solution
warning, this isn't very pretty but it allowed me to remove repetitive execution code
1) in the base class
virtual void LoadCube(UtpBipCube<float> &Cube,long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<unsigned short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
2) and in the child classes
void LoadCube(UtpBipCube<float> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1)
{ LoadAnyCube(Cube,LowerLeftRow,LowerLeftColumn,UpperRightRow,UpperRightColumn,LowerBand,UpperBand); }
void LoadCube(UtpBipCube<short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1)
{ LoadAnyCube(Cube,LowerLeftRow,LowerLeftColumn,UpperRightRow,UpperRightColumn,LowerBand,UpperBand); }
void LoadCube(UtpBipCube<unsigned short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1)
{ LoadAnyCube(Cube,LowerLeftRow,LowerLeftColumn,UpperRightRow,UpperRightColumn,LowerBand,UpperBand); }
template<class T>
void LoadAnyCube(UtpBipCube<T> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1);
Note that LoadAnyCube is not declared in the base class.
Here's another stack overflow answer with a work around:
need a virtual template member workaround.
The following code can be compiled and runs properly, using MinGW G++ 3.4.5 on Window 7:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class A{
public:
virtual void func1(const T& p)
{
cout<<"A:"<<p<<endl;
}
};
template <typename T>
class B
: public A<T>
{
public:
virtual void func1(const T& p)
{
cout<<"A<--B:"<<p<<endl;
}
};
int main(int argc, char** argv)
{
A<string> a;
B<int> b;
B<string> c;
A<string>* p = &a;
p->func1("A<string> a");
p = dynamic_cast<A<string>*>(&c);
p->func1("B<string> c");
B<int>* q = &b;
q->func1(3);
}
and the output is:
A:A<string> a
A<--B:B<string> c
A<--B:3
And later I added a new class X:
class X
{
public:
template <typename T>
virtual void func2(const T& p)
{
cout<<"C:"<<p<<endl;
}
};
When I tried to use class X in main() like this:
X x;
x.func2<string>("X x");
g++ report the following error:
vtempl.cpp:34: error: invalid use of `virtual' in template declaration of `virtu
al void X::func2(const T&)'
So it is obvious that:
virtual member function can be used in a class template. It is easy for compiler to construct vtable
It is impossible to define a class template member function as virtual, as you can see, it hard to determine function signature and allocate vtable entries.
No they can't. But:
template<typename T>
class Foo {
public:
template<typename P>
void f(const P& p) {
((T*)this)->f<P>(p);
}
};
class Bar : public Foo<Bar> {
public:
template<typename P>
void f(const P& p) {
std::cout << p << std::endl;
}
};
int main() {
Bar bar;
Bar *pbar = &bar;
pbar -> f(1);
Foo<Bar> *pfoo = &bar;
pfoo -> f(1);
};
has much the same effect if all you want to do is have a common interface and defer implementation to subclasses.
No, template member functions cannot be virtual.
In the other answers the proposed template function is a facade and doesn't offer any practical benefit.
Template functions are useful for writing code only once using
different types.
Virtual functions are useful for having a common interface for different classes.
The language doesn't allow virtual template functions but with a workaround it is possible to have both, e.g. one template implementation for each class and a virtual common interface.
It is however necessary to define for each template type combination a dummy virtual wrapper function:
#include <memory>
#include <iostream>
#include <iomanip>
//---------------------------------------------
// Abstract class with virtual functions
class Geometry {
public:
virtual void getArea(float &area) = 0;
virtual void getArea(long double &area) = 0;
};
//---------------------------------------------
// Square
class Square : public Geometry {
public:
float size {1};
// virtual wrapper functions call template function for square
virtual void getArea(float &area) { getAreaT(area); }
virtual void getArea(long double &area) { getAreaT(area); }
private:
// Template function for squares
template <typename T>
void getAreaT(T &area) {
area = static_cast<T>(size * size);
}
};
//---------------------------------------------
// Circle
class Circle : public Geometry {
public:
float radius {1};
// virtual wrapper functions call template function for circle
virtual void getArea(float &area) { getAreaT(area); }
virtual void getArea(long double &area) { getAreaT(area); }
private:
// Template function for Circles
template <typename T>
void getAreaT(T &area) {
area = static_cast<T>(radius * radius * 3.1415926535897932385L);
}
};
//---------------------------------------------
// Main
int main()
{
// get area of square using template based function T=float
std::unique_ptr<Geometry> geometry = std::make_unique<Square>();
float areaSquare;
geometry->getArea(areaSquare);
// get area of circle using template based function T=long double
geometry = std::make_unique<Circle>();
long double areaCircle;
geometry->getArea(areaCircle);
std::cout << std::setprecision(20) << "Square area is " << areaSquare << ", Circle area is " << areaCircle << std::endl;
return 0;
}
Output:
Square area is 1, Circle area is 3.1415926535897932385
Try it here
To answer the second part of the question:
If they can be virtual, what is an example of a scenario in which one would use such a function?
This is not an unreasonable thing to want to do. For instance, Java (where every method is virtual) has no problems with generic methods.
One example in C++ of wanting a virtual function template is a member function that accepts a generic iterator. Or a member function that accepts a generic function object.
The solution to this problem is to use type erasure with boost::any_range and boost::function, which will allow you to accept a generic iterator or functor without the need to make your function a template.
While an older question that has been answered by many I believe a succinct method, not so different from the others posted, is to use a minor macro to help ease the duplication of class declarations.
// abstract.h
// Simply define the types that each concrete class will use
#define IMPL_RENDER() \
void render(int a, char *b) override { render_internal<char>(a, b); } \
void render(int a, short *b) override { render_internal<short>(a, b); } \
// ...
class Renderable
{
public:
// Then, once for each on the abstract
virtual void render(int a, char *a) = 0;
virtual void render(int a, short *b) = 0;
// ...
};
So now, to implement our subclass:
class Box : public Renderable
{
public:
IMPL_RENDER() // Builds the functions we want
private:
template<typename T>
void render_internal(int a, T *b); // One spot for our logic
};
The benefit here is that, when adding a newly supported type, it can all be done from the abstract header and forego possibly rectifying it in multiple source/header files.
There is a workaround for 'virtual template method' if set of types for the template method is known in advance.
To show the idea, in the example below only two types are used (int and double).
There, a 'virtual' template method (Base::Method) calls corresponding virtual method (one of Base::VMethod) which, in turn, calls template method implementation (Impl::TMethod).
One only needs to implement template method TMethod in derived implementations (AImpl, BImpl) and use Derived<*Impl>.
class Base
{
public:
virtual ~Base()
{
}
template <typename T>
T Method(T t)
{
return VMethod(t);
}
private:
virtual int VMethod(int t) = 0;
virtual double VMethod(double t) = 0;
};
template <class Impl>
class Derived : public Impl
{
public:
template <class... TArgs>
Derived(TArgs&&... args)
: Impl(std::forward<TArgs>(args)...)
{
}
private:
int VMethod(int t) final
{
return Impl::TMethod(t);
}
double VMethod(double t) final
{
return Impl::TMethod(t);
}
};
class AImpl : public Base
{
protected:
AImpl(int p)
: i(p)
{
}
template <typename T>
T TMethod(T t)
{
return t - i;
}
private:
int i;
};
using A = Derived<AImpl>;
class BImpl : public Base
{
protected:
BImpl(int p)
: i(p)
{
}
template <typename T>
T TMethod(T t)
{
return t + i;
}
private:
int i;
};
using B = Derived<BImpl>;
int main(int argc, const char* argv[])
{
A a(1);
B b(1);
Base* base = nullptr;
base = &a;
std::cout << base->Method(1) << std::endl;
std::cout << base->Method(2.0) << std::endl;
base = &b;
std::cout << base->Method(1) << std::endl;
std::cout << base->Method(2.0) << std::endl;
}
Output:
0
1
2
3
NB:
Base::Method is actually surplus for real code (VMethod can be made public and used directly).
I added it so it looks like as an actual 'virtual' template method.
At least with gcc 5.4 virtual functions could be template members but has to be templates themselves.
#include <iostream>
#include <string>
class first {
protected:
virtual std::string a1() { return "a1"; }
virtual std::string mixt() { return a1(); }
};
class last {
protected:
virtual std::string a2() { return "a2"; }
};
template<class T> class mix: first , T {
public:
virtual std::string mixt() override;
};
template<class T> std::string mix<T>::mixt() {
return a1()+" before "+T::a2();
}
class mix2: public mix<last> {
virtual std::string a1() override { return "mix"; }
};
int main() {
std::cout << mix2().mixt();
return 0;
}
Outputs
mix before a2
Process finished with exit code 0
My current solution is the following (with RTTI disabled - you could use std::type_index, too):
#include <type_traits>
#include <iostream>
#include <tuple>
class Type
{
};
template<typename T>
class TypeImpl : public Type
{
};
template<typename T>
inline Type* typeOf() {
static Type* typePtr = new TypeImpl<T>();
return typePtr;
}
/* ------------- */
template<
typename Calling
, typename Result = void
, typename From
, typename Action
>
inline Result DoComplexDispatch(From* from, Action&& action);
template<typename Cls>
class ChildClasses
{
public:
using type = std::tuple<>;
};
template<typename... Childs>
class ChildClassesHelper
{
public:
using type = std::tuple<Childs...>;
};
//--------------------------
class A;
class B;
class C;
class D;
template<>
class ChildClasses<A> : public ChildClassesHelper<B, C, D> {};
template<>
class ChildClasses<B> : public ChildClassesHelper<C, D> {};
template<>
class ChildClasses<C> : public ChildClassesHelper<D> {};
//-------------------------------------------
class A
{
public:
virtual Type* GetType()
{
return typeOf<A>();
}
template<
typename T,
bool checkType = true
>
/*virtual*/void DoVirtualGeneric()
{
if constexpr (checkType)
{
return DoComplexDispatch<A>(this, [&](auto* other) -> decltype(auto)
{
return other->template DoVirtualGeneric<T, false>();
});
}
std::cout << "A";
}
};
class B : public A
{
public:
virtual Type* GetType()
{
return typeOf<B>();
}
template<
typename T,
bool checkType = true
>
/*virtual*/void DoVirtualGeneric() /*override*/
{
if constexpr (checkType)
{
return DoComplexDispatch<B>(this, [&](auto* other) -> decltype(auto)
{
other->template DoVirtualGeneric<T, false>();
});
}
std::cout << "B";
}
};
class C : public B
{
public:
virtual Type* GetType() {
return typeOf<C>();
}
template<
typename T,
bool checkType = true
>
/*virtual*/void DoVirtualGeneric() /*override*/
{
if constexpr (checkType)
{
return DoComplexDispatch<C>(this, [&](auto* other) -> decltype(auto)
{
other->template DoVirtualGeneric<T, false>();
});
}
std::cout << "C";
}
};
class D : public C
{
public:
virtual Type* GetType() {
return typeOf<D>();
}
};
int main()
{
A* a = new A();
a->DoVirtualGeneric<int>();
}
// --------------------------
template<typename Tuple>
class RestTuple {};
template<
template<typename...> typename Tuple,
typename First,
typename... Rest
>
class RestTuple<Tuple<First, Rest...>> {
public:
using type = Tuple<Rest...>;
};
// -------------
template<
typename CandidatesTuple
, typename Result
, typename From
, typename Action
>
inline constexpr Result DoComplexDispatchInternal(From* from, Action&& action, Type* fromType)
{
using FirstCandidate = std::tuple_element_t<0, CandidatesTuple>;
if constexpr (std::tuple_size_v<CandidatesTuple> == 1)
{
return action(static_cast<FirstCandidate*>(from));
}
else {
if (fromType == typeOf<FirstCandidate>())
{
return action(static_cast<FirstCandidate*>(from));
}
else {
return DoComplexDispatchInternal<typename RestTuple<CandidatesTuple>::type, Result>(
from, action, fromType
);
}
}
}
template<
typename Calling
, typename Result
, typename From
, typename Action
>
inline Result DoComplexDispatch(From* from, Action&& action)
{
using ChildsOfCalling = typename ChildClasses<Calling>::type;
if constexpr (std::tuple_size_v<ChildsOfCalling> == 0)
{
return action(static_cast<Calling*>(from));
}
else {
auto fromType = from->GetType();
using Candidates = decltype(std::tuple_cat(std::declval<std::tuple<Calling>>(), std::declval<ChildsOfCalling>()));
return DoComplexDispatchInternal<Candidates, Result>(
from, std::forward<Action>(action), fromType
);
}
}
The only thing I don't like is that you have to define/register all child classes.
I have looked at all the 14 answers, Some have reasons why virtual templates functions can't work, others show a work around. One answer even showed that virtual classes can have virtual functions. Which shouldn't be too surprising.
My answer will give a straight up reason why the standard doesn't allow virtual templated functions. Since so many have been complaining. Firstly though, I can't believe that some people have commented that virtual functions can be deduced at compile time. That is the dumbest thing I ever heard.
Anyhow. I am certain that the standard dictates that a this pointer to the object is the first argument to its member function.
struct MyClass
{
void myFunction();
}
// translate to
void myFunction(MyClass*);
Now that we are clear on this. We then need to know the conversion rules for templates. A templated parameter is extremely limited to what it can implicitly convert to. I don't remember all of it, but you can check C++ Primer for complete reference. For example T* is convertible to const T*. Arrays are convertible to pointers. However, derived class is not convertible to base class as a templated parameter.
struct A {};
struct B : A {};
template<class T>
void myFunction(T&);
template<>
void myFunction<A>(A&) {}
int main()
{
A a;
B b;
myFunction(a); //compiles perfectly
myFunction((A&)b); // compiles nicely
myFunction(b); //compiler error, use of undefined template function
}
So I hope you see where I am getting at. You cannot have a virtual template function because as far as the compiler is concerned they are two completedly different functions; as their implicit this parameter is of different type.
Another reasons why virtual templates can't work are equally valid. Since virtual tables are the best way to implement virtual functions fast.
How right function is called in case of virtual?
Vtable will contain entries for each virtual function of class and at run time it will pick the address of specific function and it will call respective function.
How right function has to be called in case of virtual along with function template?
In case of function template, user can call this function with any type. Here same function has several versions based on type. Now, in this case for same function because of different versions, many entries in vtable has to be maintained.