Determination of type in function template
I would like to ask you for an advice about function template. I have a function that adds some data into buffer. But I need also to add an information about data type into the buffer. The type of data is a following enum:
enum ParameterType
{
UINT,
FLOAT,
DOUBLE
};
And I need to create a function template from function like this:
void SomeBuffer::append( double par )
{
appendType( DOUBLE );
memcpy( pStr + _length, &par, sizeof( double ) );
_len开发者_JS百科gth += sizeof( double );
appendType( DOUBLE );
}
Could you please advice me how to pass a value from ParameterType for appendType() depending on type of parameter.
template<class T>
void SomeBuffer::append( T par )
{
appendType( ??? );
memcpy( pStr + _length, &par, sizeof( T ) );
_length += sizeof( T );
appendType( ??? );
}
I tried to do it by some macros but without success. Thank you very much for any advice.
You can do what you want by introducing an additional class template that will map the type to the enumeration constant that you need as in the following example (without FLOAT for brevity):
enum ParameterType
{
UINT,
DOUBLE
};
template <typename T>
struct GetTypeCode;
template <>
struct GetTypeCode<double>
{
static const ParameterType Value = DOUBLE;
};
template <>
struct GetTypeCode<unsigned>
{
static const ParameterType Value = UINT;
};
template <typename T>
void SomeBuffer::append(T par)
{
appendType(GetTypeCode<T>::Value);
memcpy(pStr + _length, &par, sizeof(T));
_length += sizeof(T);
appendType(GetTypeCode<T>::Value);
}
Since specializations of GetTypeCode will be almost identical you may introduce a macro for defining them, e.g.
#define MAP_TYPE_CODE(Type, ID) \
template <> \
struct GetTypeCode<Type> \
{ \
static const ParameterType Value = ID; \
};
MAP_TYPE_CODE(double, DOUBLE)
MAP_TYPE_CODE(unsigned, UINT)
template <typename T> struct identity { };
inline void appendType_(identity<double> ) { appendType(DOUBLE); }
inline void appendType_(identity<unsigned>) { appendType(UINT); }
inline void appendType_(identity<MyType> ) { appendType(MY_TYPE); }
Then use it like so:
template<class T>
void SomeBuffer::append( T par )
{
appendType_( identity<T>() );
memcpy( pStr + _length, &par, sizeof( T ) );
_length += sizeof( T );
appendType_( identity<T>() );
}
You could also combine this with @vitaut's idea of getting the type code separately, and passing it to appendType
.
inline ParameterType typeCode(identity<double> ) { return DOUBLE; }
inline ParameterType typeCode(identity<unsigned>) { return UINT; }
inline ParameterType typeCode(identity<MyType> ) { return MY_TYPE; }
...
appendType(typeCode(identity<T>()));
EDIT: Thanks to @Johannes for the identity<T>
suggestion.
A different approach to that given by Marcelo Cantos would be creating a metafunction:
template <typename T>
struct my_type_id; // undefined as to trigger compiler error for unknown types
template <>
struct my_type_id<double> {
static const ParameterType value = DOUBLE;
};
template <>
struct my_type_id<float> {
static const ParameterType value = float;
};
And then using that to resolve the enumerated value:
template<class T>
void SomeBuffer::append( T par )
{
appendType( my_type_id<T>::value );
memcpy( pStr + _length, &par, sizeof( T ) );
_length += sizeof( T );
appendType( my_type_id<T>::value );
}
The actual definition of the traits can be defined in a macro:
#define TYPE_ID_MAP( type, val ) \
template <> struct my_type_id<type> { \
const static ParameterType value = val;\
}
template <typename T>
struct my_type_id; // undefined as to trigger compiler error for unknown types
TYPE_ID_MAP( double, DOUBLE );
TYPE_ID_MAP( float, FLOAT );
TYPE_ID_MAP( unsigned int, UINT );
精彩评论