2010-10-29 2 views
2

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

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

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

+1

Предупреждение. Сериализация объектов с помощью функции 'memcpy()' вызовет у вас проблемы, если машина, которая читает буфер, имеет другую конечность, чем машина, которая пишет буфер. –

ответ

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

Вы также можете совместить это с идеей @ Витовт о получении кода типа отдельно, и передавая ее 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: Благодаря @Johannes для identity<T> предложение.

+0

в этом случае простые перегрузки могут иметь больше смысла, чем полные специализации. См. Http://www.gotw.ca/publications/mill17.htm – Flexo

+0

@awoodland: Спасибо за подсказку. Я только что добрался до этой идеи, когда появился ваш комментарий. –

+0

У этого решения есть проблема, связанная с продвижением по службе при вызове 'appendType_' или' typeCode', вставляется некорректный код типа, например, при вызове 'append' для некоторого типа класса, который имеет неявное преобразование в' unsigned int'. –

7

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

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) 
2

Другой подход к тому, что данный Марсело Cantos будет создание 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; 
}; 

А затем с помощью, чтобы решить перечисляемого значение:

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); 
Смежные вопросы