Jürgen Kaminski <jk*******@freenet.de> wrote in message news:<cja14v$m4u$03[snip]
Thanks for your help. If I understand this correctly (and I'm not sure
if I do) then I will need in the base class a stub for each type and
each operation (?) This does not work for virtual functions that return
any of t1,t2,t3,t4, does it?
What you say is true but you can indirectly work around this.
My intention was not to use class Data<> directly but to create a
container of them e.g:
template<class _Traits=_Traits<T1,T2,T3,T4> >
class DataContainer{
//handle allocation and assignments to pointers of type
bData<_Traits>;
};
But that gets pretty complicated and the allocation is the main reason
for a traits class. But not getting into the implications of a
container class I will explain how to indirectly return diferent types
of objects.
Amend the previously posted code to include conversion and assigment
operators:
template<class _Traits>
class bData{
public:
bData(){}
virtual ~bData(){}
typedef typename _Traits::type_list::head t1;
typedef typename _Traits::type_list::tail node2;
typedef typename node2::tail node3;
typedef typename node3::tail node4;
typedef typename node2::head t2;
typedef typename node3::head t3;
typedef typename node4::head t4;
virtual bData& operator=(const t1&){return *this;}
virtual bData& operator=(const t2&){return *this;}
virtual bData& operator=(const t3&){return *this;}
virtual bData& operator=(const t4&){return *this;}
virtual operator t1(){return t1();}
virtual operator t2(){return t2();}
virtual operator t3(){return t3();}
virtual operator t4(){return t4();}
};
template<class T,class _Traits=Traits<T1,T2,T3,T4> >
class Data:public bData<_Traits>{
public:
Data(){}
~Data(){}
Data(const Data& rhs){itsData = rhs.itsData;}
Data(T& d){itsData = d;}
Data& operator=(const T& rhs){itsData=rhs; return *this;}
operator T(){return itsData;}
private:
T itsData;
};
Although you cannot directly call for an objects data you can extract
a copy now.
Using a simple test class like the following here is an example:
class A{
public:
A():x(0){std::cout<<"A()\n";}
A(int a):x(a){std::cout<<"A(int)\n";}
~A(){std::cout<<"~A()\n";}
A(const A& rhs){x=rhs.x; std::cout<<"A(const A&)\n";}
operator int(){return x;}
private:
int x;
};
int main(){
typedef Traits<int,A,bool,double> type_traits;
bData<type_traits>* p = new Data<A, type_traits>;
A a=5;
*p = a; //Assigment example
A b = *p;
std::cout<< b << std::endl;
delete p;
p = new Data<double, type_traits>;
double c = *p = 6.6;
int x = *p = 7; //Unhandled Error, 7 is an int thus x is undefined.
double d = *p;
std::cout<< d << std::endl;
delete p;
return 0;
}
As you can see a copy of the object(no matter what type it is) can be
created. Then you can do what you want with the copy then reapply it
to the original if you wanted to.
you can create traits like is_convertable_to_int<T> then apply this to
a type_list to create direct conversion for example:
bData<type_traits>* p = new Data<A, type_traits>;
*p = 5;
Although A can convert to an int it won't bubble as A is not an int
type but you can , from within the virtual stub, ask the object if it
can convert. By using traits and type_lists the object can check to
see if it is a member of ,in this case int_types(a type_list of all
int types), and if it is a memeber assign the integer directly to
itself. It should only be a member of int_types if it can convert from
int.
Not sure if I explained the above well but if you understand it you
probably ask but what if it can't convert. This is a design issue and
perhaps you want to treat this as an error or let it go as in the
example where int type was assigned to a double.
you may wish to let it go unnoticed so that you could do something
like this:
for(int i=0 ; i<containerlenght; i++){
dataContainer[i] = "A string";
}
Then all types that were in type_list string_types would be assigned
to but all the non-convertable_to_string types would be left
untouched.
The problem I found with creating this type of container is with these
kind of design choices.
HTH
Paul.