Abstract base class requires a virtual template: fixes?

D

Dom Jackson

Hello -

I have a problem where I need to test some numeric code using a
variety of built-in integer types:

obj_type1 = obj_type2 OP obj_type3; // is obj_type1 correct?

If I test with 10 built-in integer types, then I get 1000 permutations
of the above statement. If I then test a dozen different operators, I
get over 10,000 test operations.

Obviously, I need some generic way to handle this. I can't immediately
see a static/template-based solution, but it seems like I should be
able to do this dynamically. My first pass at a solution looks like:

1 - define an 'integer object' abstract base class, IntObject

2 - define a virtual templated method 'get()' in IntObject, which
returns a pointer to an object of a templated integer type

3 - define a derived class for each integer type of interest; this
stores an object of that type, and defines the virtual 'get()'
function to return a pointer to this object

4 - my test code can now declare an array of IntObject pointers, and
can randomly select a pointer in this array. Calling the 'get()'
method then returns an object pointer of an effectively random type
for testing:

IntObject* res_array, opL_array, opR_array;
...
res_index = rand() % 10;
opL_index = rand() % 10;
opR_index = rand() % 10;
*(res_array[res_index]->get()) =
*(opL_array[opL_index]->get()) OP *(opR_array[opR_index]->get());

The problem is, this doesn't work, because C++ doesn't allow templated
virtuals:

class IntObject {
public:
template<typename T>
virtual T* get(void) const = 0; // ERROR
};

Any ideas on how I can get around this problem, or any better
solutions?

Many thanks -

Dom
 
D

dasjotre

Hello -

I have a problem where I need to test some numeric code using a
variety of built-in integer types:

obj_type1 = obj_type2 OP obj_type3; // is obj_type1 correct?

If I test with 10 built-in integer types, then I get 1000 permutations
of the above statement. If I then test a dozen different operators, I
get over 10,000 test operations.

Obviously, I need some generic way to handle this. I can't immediately
see a static/template-based solution, but it seems like I should be
able to do this dynamically. My first pass at a solution looks like:

1 - define an 'integer object' abstract base class, IntObject

2 - define a virtual templated method 'get()' in IntObject, which
returns a pointer to an object of a templated integer type

3 - define a derived class for each integer type of interest; this
stores an object of that type, and defines the virtual 'get()'
function to return a pointer to this object

4 - my test code can now declare an array of IntObject pointers, and
can randomly select a pointer in this array. Calling the 'get()'
method then returns an object pointer of an effectively random type
for testing:

IntObject* res_array, opL_array, opR_array;
...
res_index = rand() % 10;
opL_index = rand() % 10;
opR_index = rand() % 10;
*(res_array[res_index]->get()) =
*(opL_array[opL_index]->get()) OP *(opR_array[opR_index]->get());

The problem is, this doesn't work, because C++ doesn't allow templated
virtuals:

also, there is no way for a compiler to deduce T from call to get().
class IntObject {
public:
template<typename T>
virtual T* get(void) const = 0; // ERROR

};

Any ideas on how I can get around this problem, or any better
solutions?

not as easy as you've tried. look up some sort of variant
like boost::variant

say you have int and long integer types to work with

typedef boost::variant<int, long> my_integer;

provide visitor for each operation and each
type combination (sorry).

struct plus_visitor : public boost::static_visitor<my_integer>
{
my_integer operator()(int i, int j) const
{
return my_integer(i+j);
}
my_integer operator()(long i, long j) const
{
return my_integer(i+j);
}
my_integer operator()(int i, long j) const
{
return my_integer((long)i+j);
}

my_integer operator()(long i, int j) const
{
return my_integer(i+(long)j);
}
};

it also works for template operators if you can
treat types generically

struct reveal : public boost::static_visitor<void>
{
template<class T>
void operator()(T const & t) const
{
std::cout << t <<'\n';
}
};

int main()
{
my_integer i(1); // hold int
my_integer j(1L); // holds long

// k = i + j;
my_integer k = ::boost::apply_visitor(plus_visitor(), i, j);

::boost::apply_visitor(reveal(), k);
}

That is the best I can think of.
Many thanks -

Dom

regards

DS
 
M

Michael DOUBEZ

Dom Jackson a écrit :
Hello -

I have a problem where I need to test some numeric code using a
variety of built-in integer types:

obj_type1 = obj_type2 OP obj_type3; // is obj_type1 correct?

If I test with 10 built-in integer types, then I get 1000 permutations
of the above statement. If I then test a dozen different operators, I
get over 10,000 test operations.

Obviously, I need some generic way to handle this. I can't immediately
see a static/template-based solution, but it seems like I should be
able to do this dynamically. [snip]

Perhaps a typelist is what you need. Giving an example with addition:

//generic typelist system
template <typename T1, typename T2>
struct TypeList
{
typedef T1 Head;
typedef T2 Tail;
};
//end of list type
struct NullType {};

// define a list with your types
typedef TypeList<long, TypeList<int, TypeList<short, NullType> > > IntList;

//implementation of the plus operation as recursive template
template < typename TList1 , typename TList2 , typename TListIni> struct
plus_operation_imp;

//general case of recursion
template < typename T1, typename T2 , typename T3, typename T4 ,
typename TListIni>
struct plus_operation_imp< TypeList<T1, T2> , TypeList<T3, T4> ,
TListIni > :
public plus_operation_imp< TypeList<T1, T2> , T4, TListIni>
{
T1 operator()(T1 lhs,T3 rhs)
{
return lhs+rhs;
}
};

//recursion at end of list for right hand side
template < typename T1, typename T2 , typename T3 , typename TListIni>
struct plus_operation_imp< TypeList<T1, T2> , TypeList<T3, NullType>
,TListIni> :
public plus_operation_imp< T2 , TListIni, TListIni>
{
T1 operator()(T1 lhs,T3 rhs)
{
return lhs+rhs;
}
};
//recursion at end of both list
template < typename T1, typename T3 , typename TListIni>
struct plus_operation_imp< TypeList<T1, NullType> , TypeList<T3,
NullType> , TListIni>
{
T1 operator()(T1 lhs,T3 rhs)
{
return lhs+rhs;
}
};

//type to initialize recursion
template<typename TList>
struct plus_operation: public plus_operation_imp<TList,TList,TList>
{};

//here is your functor
plus_operation<IntList> myoperation;

Then you can call myoperation with any combinaison of parameters.
myoperation(long,long);
myoperation(long,int);
myoperation(int,int);
myoperation(int,long);
....

You might even automatize that with MPL but I am not familiar enough
with it to tell you.

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,222
Messages
2,571,141
Members
47,756
Latest member
JulienneY0

Latest Threads

Top