Re: message processing using template
{ Please provide at least some context with one or more small
quotes from the article you're replying to -mod }
As you can see, vast majority of the information is actually only
available at run-time. That means that the part that you can actually
do at compile time, is to
- automatically establish the type selection,
- automatically associate user-defined type-id with a given type
- call the appropriate handler in a user-defined functor, given
that it provides an overload for all the expected types
The run-time type selection is effectively 'emulates' the switch-case
(actually an if-elseif-else) construct. It will not be pretty for
sure, so unless you'll work with a very volatile set of types that
can appear in the binary file, it is probably not worth it.
Anyway, the basic building blocks that you'll need:
- a run-time, user-defined type-id (e.g. int type in your example)
- a type-list that contains all the types appearing in the file
- a base class that
- acts as a base-class for user-defined types, that contains the
type-id member data, and initializes at run-time with the
appropriate type-id (derived from the type-list position)
- entry point to process the input (let's call it process())
- a tryProcess functor that establishes the if-elseif-else construct by
recursively calling itself and iterating through the type-list,
with a termination case if the type is not present
template < typename Derived, typename TypeList >
struct BinaryInterface
{
int const type_id;
typedef TypeList DefinedTypes;
// in ctr initialize type_id with the Derived type's position
// inside the type-list (DefinedTypes)
// see mpl::vector, mpl::find and boost::is_same
// static function to read from raw input
// (e.g. mem-location in this case)
template< typename FunT >
static FunT process( void * & input, FunT functor )
{
return Internal::tryProcess<
mpl::size< DefinedTypes >::value - 1, BinaryInterface
>()( input, functor );
}
};
The tryProcess can be something along these lines:
template < std::size_t N, typename BinaryInterfaceT >
struct tryProcess
{
typedef typename BinaryInterfaceT::DefinedTypes DefinedTypes;
// current type at position N in the type-list
typedef typename mpl::at< DefinedTypes, mpl::int_< N > >::type
DerivedType;
template< typename FunT >
FunT operator()( void * & input, FunT functor )
{
// is this the type we are looking for?
if ( static_cast< BinaryInterfaceT * >( input )->type_id == N )
{
// get a typed ptr out of input
DerivedType * derivedInput =
static_cast< DerivedType * > ( input );
// tell the user-defined functor the last read-size
// and the advance the pointer appropriately
reinterpret_cast< char * & >( input )
+= functor.readSize = sizeof( DerivedType );
// execute the user-defined functor on the last object we read
// it needs to overload the operator() for all expected types
functor( derivedInput );
return functor;
}
// nope, keep looking
else
{
return tryProcess< N-1, BinaryInterfaceT >()( input, functor );
}
}
};
// partial-specialization for the termination case
// the 0th position in the type-list is reserved for the error case
// this is not really needed if you are willing to play with indeces
template< typename BinaryInterfaceT >
struct tryProcess< 0, BinaryInterfaceT >
{
template< typename FunT >
FunT operator()( void * & input, FunT functor )
{
throw OutOfBound(
static_cast< BinaryInterfaceT * >( input ) -> type_id
);
return functor; // never executed, but to prevent warnings
}
};
And finally the type-list is:
typedef boost::mpl::vector<
boost::mpl::void_ // placeholder, place types after this
, MyType1
, MyType2
MyTypeList;
HTH
-- Zoltan
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]