Lookup derived template type
I've derived a template class from non-template base
struct CBaseList {
virtual size_t Size() = 0;
};
template <class T>
struct CPointList : public BaseList {
virtual size_t Size() { return mData.size(); }
std::vector <T> mData;
};
// Ok, now I can create various instances
CBaseList * lst1 = new CPointList<float> ();
CBaseList * lst2 = new CPointList<double> ();
But how can I copy/assign values between different instances? For example
template <class T1, class T2>
void CopyVec( const T1 & src, T2 & dst )
{
dst.resize(src.size());
for (size_t i = 0; i < src.size(); ++i)
dst[i] = src[i];
}
void CopyList( const CBaseList * src, CBaseList * dst )
{
// How to call CopyVec ?
}
If I cast CBaseList(s) to any derived class, then I've a big ugly "switch". Are there better solutions?
Thanks Igor
thiton
Thanks for your replies. I realize any compiler should see/have types to generate code from template - no other way. But how to implement it co开发者_StackOverflow社区mpactly and once, without replicating for any needed template function? I'm thinking about a sketch like:
// caller
theWrapper(lst1, lst2)->mInstance().DoCopy(lst1, lst2, num);
// mInstance type
template <class T1, class T2>
struct CWrapInstance {
void DoCopy( CBaseList * lst1, CBaseList * lst2, size_t num )
{
// cast types and call original template
Copy(((T1 *) lst1)->mData, ((T2 *) lst2)->mData, num);
}
};
So for every new template I need to add only a small method to CWrapInstance. But how to design "theWrapper" ?
Thx for your understanding. Igor
In C++ there is no way to pass a type around at run-time. Types are not first class objects, types only exist at compile time.
What you can do is passing around type names (e.g. typeid
, or you can create your own enumeration and you can add a virtual method to your container that returns this enumerated value).
Machine code that does for example the conversion from double
to float
is clearly different from machine code that does the conversion from int
to unsigned long long
and please remember that C++ programs cannot create new code at run time, all the machine code you may need at run time must have been created at compile time.
This means that if you need to create a polymorphic data container (meaning run-time polymorphism) and you want to provide conversion/assignment between instances then the code for all possible conversion combinations must be created in advance at compile time and you must also select the code to run using type names.
So Yes. Unfortunately you need a switch or something similar.
A possible alternative to a switch is to create a map of conversion functions... e.g.
std::map< std::pair<int, int>, void (*)(CBaseList *, CBaseList *) > converters;
that given two type names returns the address of a conversion function, so that you can then store in the map all the conversions you are going to need:
template<typename U, typename V>
void assign(CBaseList *u, CBaseList *v)
{
CPointList<U>* pu = dynamic_cast< CPointList<U> >(u);
CPointList<V>* pv = dynamic_cast< CPointList<V> >(v);
...
}
void init_converters()
{
converters[std::make_pair(FLOAT_ID, DOUBLE_ID)] = &assign<float, double>;
converters[std::make_pair(INT_ID, DOUBLE_ID)] = &assign<int, double>;
...
}
then you can assign dynamically at runtime with
converters[std::make_pair(a->id(), b->id())](a, b);
I do not think you can avoid the glorified switch, and 6502 posted a good alternative to perform it. The problem is that your types are not formally related in any way, so you actually need n^2 conversion functions that need to be instantiated from templates, which can't be done at run-time. I'd recommend a different design?
精彩评论