Определение типа в шаблоне функции - PullRequest
2 голосов
/ 29 октября 2010

Я бы хотел попросить у вас совета по шаблону функции. У меня есть функция, которая добавляет некоторые данные в буфер. Но мне также нужно добавить информацию о типе данных в буфер. Тип данных следующий перечисление:

enum ParameterType
{
   UINT,
   FLOAT,
   DOUBLE
};

И мне нужно создать шаблон функции из этой функции:

void SomeBuffer::append( double par )
{
    appendType( DOUBLE );
    memcpy( pStr + _length, &par, sizeof( double ) );
    _length += sizeof( double );
    appendType( DOUBLE );
}

Подскажите, пожалуйста, как передать значение из ParameterType для appendType () в зависимости от типа параметра.

template<class T>
void SomeBuffer::append( T par )
{    
    appendType( ??? );
    memcpy( pStr + _length, &par, sizeof( T ) );
    _length += sizeof( T );
    appendType( ??? );
}

Я пытался сделать это с помощью некоторых макросов, но безуспешно. Большое спасибо за любой совет.

Ответы [ 3 ]

7 голосов
/ 29 октября 2010

Вы можете сделать то, что вы хотите, введя дополнительный шаблон класса, который отобразит тип на нужную константу перечисления, как в следующем примере (без FLOAT для краткости):

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);
}

Поскольку специализации GetTypeCode будут практически идентичны, вы можете ввести макрос для их определения, например,

#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)
4 голосов
/ 29 октября 2010
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); }

Затем используйте его следующим образом:

template<class T>
void SomeBuffer::append( T par )
{    
    appendType_( identity<T>() );
    memcpy( pStr + _length, &par, sizeof( T ) );
    _length += sizeof( T );
    appendType_( identity<T>() );
}

Вы также можете объединить это с идеей @ vitaut - получить код типа отдельно и передать его в appendType.

* 1007.*

РЕДАКТИРОВАТЬ: Спасибо @Johannes за предложение identity<T>.

2 голосов
/ 29 октября 2010

Другим подходом, предложенным Марсело Кантосом, было бы создание метафункции:

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;
};

И затем использование этого для разрешения перечисляемого значения:

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 );
}

Фактическое определениечерты могут быть определены в макросе:

#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 );
...