Simplified I have the following class hierarchy:
class BaseVec {
public:
BaseVec() {};
virtual ~BaseVec() {};
virtual double get_double(int i) con
Why not change foo_templat
e to be:
template<typename T>
double foo_template(Vec<T>*) {
// use v which involves calling get
return result;
}
and foo
to be:
template<typename T>
double foo (Vec<T>* v )
{
return foo_template(v)
}
and let argument deduction do the work?
(You can probably get rid of one of the functions, but I wanted to keep is as close to the original)
Automatic dispatch in C++ happens with runtime-polymorphism by means of virtua function and with static_type polymorphism by mnas of a static_Cast, but you need to know what type to cast.
With a different design, avoiding void*
, you can do the following:
template<class Derived>
class static_polimorphic {};
template<class A>
A& upcast(static_polymorphic<A>& sa)
{ return static_cast<A&>(sa); }
template<class A>
const A& upcast(const static_polymorphic<A>& sa)
{ return static_cast<const A&>(sa); }
Now, you classes shold be like
class C1: public static_polymorphic<C1>
{
....
};
class C2: public static_polymorphic<C2>
{
....
};
Polymorphism will then apply as
template<class A>
void function(const static_polymorphic<A>& sa)
{
A& a = upcast(sa);
a.methods();
...
}
In other words, the type is anymore represented a base member variable, but by a base template parameter.
Note also that being the bases differentiated by the derived type, common functions will not reaqire to be virtual. You can so completely avoid runtimes-based polymorphism, unless you have to store different runtime-type created object into a same container or collection.
For that purpose you can use a second non-tempetised base with abstract virtual function as "launchers" for the one in the derived classes. (May be better to use the runtime polymorphic one as first base, to simplify run-time pointer convertion, since there will be no offset)
First of all, don't use reinterpret_cast
while converting to/from pointer to polymorphic class. You can write a simple pointer wrapper which allow you to use safe casting operator static_cast
:
template <class Type>
class PointerWrapper
{
public:
PointerWrapper(Type* object);
PointerWrapper& operator=(Type* object);
Type* operator->();
protected:
Type* object;
};
template <class Type>
PointerWrapper<Type>::PointerWrapper(Type* object) :
object(object)
{
}
template <class Type>
PointerWrapper<Type>& PointerWrapper<Type>::operator=(Type* object)
{
this->object = object;
}
template <class Type>
Type* PointerWrapper<Type>::operator->()
{
return object;
}
Now you can write:
typedef PointerWrapper<BaseVec> BaseVecPointer;
template<typename T>
double foo(void* p) {
BaseVecPointer* vp = static_cast<BaseVecPointer*>(p);
// ...
// ... = (*vp)->get_double(...);
// ...
return result;
}
In this code polymorphism capabilities were used, i.e. function get_double
was called instead of calling get
.
But if you want to call just get
, not get_double
, i.e. you want to call template functions with different template arguments depending on the value of run-time variable, you can use the following method:
enum FooTypes
{
NoFooType = -1,
DoubleFooType = 0,
IntegerFooType = 1,
// ...
FooTypesCount
};
template<FooTypes fooType>
struct ChooseType
{
static
const FooTypes value = NoFooType;
typedef void Type;
};
template<>
struct ChooseType<DoubleFooType>
{
static
const FooTypes value = DoubleFooType;
typedef double Type;
};
template<>
struct ChooseType<IntegerFooType>
{
static
const FooTypes value = IntegerFooType;
typedef int Type;
};
Here you should write specializations of the class template ChooseType
for all possible values of type
variable.
Following code describes the function ChooseFoo
which selects what specialization of foo_template
function template should be called:
typedef double (*FooFunction)(void*);
template<FooTypes fooType>
FooFunction ChooseFooImpl(int type)
{
if (type == fooType)
{
if (ChooseType<fooType>::value != NoFooType)
{
return foo_template<typename ChooseType<fooType>::Type>;
}
else
{
return NULL;
}
}
else
{
return ChooseFooImpl<(FooTypes)(fooType - 1)>(type);
}
}
template<>
FooFunction ChooseFooImpl<NoFooType>(int type)
{
return NULL;
}
FooFunction ChooseFoo(int type)
{
return ChooseFooImpl<FooTypesCount>(type);
}
And this is foo
function implementation:
double foo(void* p, int type)
{
FooFunction fooFunction = ChooseFoo(type);
if (fooFunction != NULL)
{
return fooFunction(p);
}
else
{
//unsupported type
// ...
}
}