开发者

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?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜