Добрый вечер. Хочу унифицировать работу с данными разных типов. Для этого вокруг данных строится класс, который дополняет данные свойствами. Для работы с данными предусмотрены методы чтения/записи. Для каждого типа данных должна быть своя специализация. При этом, если объявляется экземпляр с типом данных, для которого нет специализации, то должна быть ошибка во время компиляции. Вот как это реализовано:
struct CValueBase
{
enum STATUS { INITED, UNKNOWN };
STATUS Status;
CValueBase() { Status = UNKNOWN; }
bool IsInited() { return Status==INITED; }
STDMETHOD(Write)(VARIANT Val) PURE;
STDMETHOD(Read)(VARIANT *pVal) PURE;
};
template<typename T>
struct CValue : public CValueBase
{
T Value;
STDMETHOD(Read)(VARIANT *pVal)
{
if ( Status==UNKNOWN ) return E_FAIL;
return CComVariant(Value).Detach(pVal);
}
STDMETHOD(Write)(VARIANT Val) PURE; // [1]
};
template<> STDMETHOD(CValue<bool>::Write)(VARIANT Val)
{
Value = Val.boolVal==VARIANT_TRUE;
return S_OK;
}
CValue<bool> test;
Если отсутствует строка, отмеченная коментарием [1], то компилятор ругается (error C2244: 'CValueBase::Write' : unable to match function definition to an existing declaration). Если строка есть, то при определении экземпляра test не используется специализация и компилятор снова ругается (error C2259: 'CValue<T>' : cannot instantiate abstract class). Что-то не пойму, что тут нетак
А>Если отсутствует строка, отмеченная коментарием [1], то компилятор ругается (error C2244: 'CValueBase::Write' : unable to match function definition to an existing declaration). Если строка есть, то при определении экземпляра test не используется специализация и компилятор снова ругается (error C2259: 'CValue<T>' : cannot instantiate abstract class). Что-то не пойму, что тут нетак
Макросы.
1) PURE — это '= 0'
2) STDMETHOD(method) это virtual HRESULT STDMETHODCALLTYPE method
Нужно переписать без них и все должно получиться.
Re[2]: Обязательная специализация классов
От:
Аноним
Дата:
20.08.09 19:46
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали: ЮЖ>Нужно переписать без них и все должно получиться.
Те же самые ошибки.
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Юрий Жмеренецкий, Вы писали: ЮЖ>>Нужно переписать без них и все должно получиться. А>Те же самые ошибки.
Именно переписать, а не выполнить работу препроцессора
Ошибки в комментариях.
Так должно компилироваться, но ошибки при инстанцировании для типов, для которых специализаци отсутствуют будут диагностироваться на этапе линковки. Для того чтобы таикие ошибки детектировались в момент инстанцирования можно сделать так (без виртуальных функций):
template<class T> struct variant_traits;
struct CValueBase
{
enum STATUS { INITED, UNKNOWN };
STATUS Status;
CValueBase() { Status = UNKNOWN; }
bool IsInited() { return Status==INITED; }
};
// Эта структура необходима для проверки наличия специализации
// variant_traits для типа T и реализаций соответствующих функций.
// Можно обойтись без нее, но тогда диагностика будет выдаваться только
// при вызове соответствующих функций CValuetemplate<class T>
struct force_check
{
force_check()
{
&variant_traits<T>::Read;
&variant_traits<T>::Write;
}
};
template<typename T>
struct CValue : CValueBase, private force_check<T>
{
HRESULT Read(VARIANT *pVal) { return variant_traits<T>::Read(pVal); }
HRESULT Write(VARIANT Val) { return variant_traits<T>::Write(Val); }
//...
};
// Специализации для каждого типаtemplate<> struct variant_traits<bool>
{
static HRESULT Read(VARIANT *pVal) { /**/}
static HRESULT Write(VARIANT Val) { /**/}
};
Re[4]: Обязательная специализация классов
От:
Аноним
Дата:
20.08.09 21:26
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Ошибки в комментариях. ЮЖ>Так должно компилироваться, но ошибки при инстанцировании для типов, для которых специализаци отсутствуют будут диагностироваться на этапе линковки.
Это то, что надо. Спасибо! На работе залогинюсь, оценочку поставлю
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Юрий Жмеренецкий, Вы писали: ЮЖ>>Нужно переписать без них и все должно получиться. А>Те же самые ошибки.
Можно не переписывать, а использовать правильным способом.
В реализации вместо STDMETHOD(...) писать STDMETHODIMP ..., а PURE просто убрать как неуместный. Метод-то не абстрактный, так зачем обманывать себя и компилятор?