tags:

views:

59

answers:

3

Hi, I have a requirement where in i have a set of classes and they have a one on one correspondence with another set of classes. Consider something like this

a)

 template < class A >

class Walkers
{
     int walk( Context< A >* context );
};

The set of Context classes are not templates. They are individual classes. I need to create a mapping between these two sets. One way, i could think of is to create a typelist and refer to the class at the appropriate location. But i feel that is more error prone, as i may mismatch the Contexts in the typelist. Can someone advise me how to do this ?

Thanks, Gokul.

A: 

Can you make the Context classes templates and use template specialization for implementing them?

Tronic
Well! That's one option, but if there is a many-to-one relationship, then template specialization might fail.
Gokul
+1  A: 

I am not sure to understand what you want to do, what your requirements or goal are, but you could try to use traits to define the relationship:

// direct mapping
template <typename T>
struct context_of;

template <>
struct context_of<A> {
   typedef ContextA type;
};

// reverse mapping
template <typename T>
struct from_context;

template <>
struct from_context< ContextA > {
   typedef A type;
};

The code you posted would be written as:

template <typename T>
class Walker {
public:
   typedef typename context_of<T>::type context_type;
   int walker( context_type* context );
};

To reduce typing you could build the mappings out of typelists (possibly complex), or you might want to use a helper macro (dirtier, simpler):

#define GENERATE_CONTEXT_ENTRY( the_class, the_context ) \
   template <> struct context_of< the_class > { \
      typedef the_context type; }; \
   template <> struct from_context< the_context > \
      typedef the_class type; };

GENERATE_CONTEXT_ENTRY( A, ContextA );
GENERATE_CONTEXT_ENTRY( B, ContextB );

#undef GENERATE_CONTEXT_ENTRY
David Rodríguez - dribeas
Thanks!! That's a nice one. That would solve my issue.
Gokul
Can you please also post the solution using typelists. just curious to know.
Gokul
A: 

Using boost::mpl:

using boost::mpl;
typedef map< pair< A, ContextA >,
             pair< B, ContextB > > context_type_map;

template <typename T>
class Walker {
public:
   typedef at< context_type_map, T >::type context_type;
   int walker( context_type* context );
};

In fact, I believe that you can use pretty much any type container (boost::mpl::vector) to store pairs and use boost::mpl::find_if with a predicate that extracts the first element of the pair and compares.

David Rodríguez - dribeas
Can you suggest me a good web page to read about boost::mpl?
Gokul
On the web you can take a look at the documentation. The reference has small usage examples that you can take a look at for simple purposes as this one. Off line, you can take a look at 'C++ Template Metaprogramming' by Dave Abrahams it has coverage of the MPL and PP libraries.
David Rodríguez - dribeas