Обязательная специализация классов
От: Аноним  
Дата: 20.08.09 18:42
Оценка:
Добрый вечер. Хочу унифицировать работу с данными разных типов. Для этого вокруг данных строится класс, который дополняет данные свойствами. Для работы с данными предусмотрены методы чтения/записи. Для каждого типа данных должна быть своя специализация. При этом, если объявляется экземпляр с типом данных, для которого нет специализации, то должна быть ошибка во время компиляции. Вот как это реализовано:
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). Что-то не пойму, что тут нетак
Re: Обязательная специализация классов
От: Юрий Жмеренецкий ICQ 380412032
Дата: 20.08.09 19:36
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>struct CValueBase
...

А>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) PURE — это '= 0'
2) STDMETHOD(method) это virtual HRESULT STDMETHODCALLTYPE method

Нужно переписать без них и все должно получиться.
Re[2]: Обязательная специализация классов
От: Аноним  
Дата: 20.08.09 19:46
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Нужно переписать без них и все должно получиться.
Те же самые ошибки.
Re[3]: Обязательная специализация классов
От: Юрий Жмеренецкий ICQ 380412032
Дата: 20.08.09 20:33
Оценка: 3 (1)
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>>Нужно переписать без них и все должно получиться.
А>Те же самые ошибки.

Именно переписать, а не выполнить работу препроцессора

struct CValueBase
{
  //...
  virtual HRESULT Write(VARIANT Val) = 0;
};


template<typename T>
struct CValue : public CValueBase
{
  //...
  virtual HRESULT Write(VARIANT Val) /*= 0*/ ;
};

template<> 
/*virtual*/ HRESULT CValue<bool>::Write(VARIANT Val)
{
  //...
}


Ошибки в комментариях.
Так должно компилироваться, но ошибки при инстанцировании для типов, для которых специализаци отсутствуют будут диагностироваться на этапе линковки. Для того чтобы таикие ошибки детектировались в момент инстанцирования можно сделать так (без виртуальных функций):
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 и реализаций соответствующих функций.
// Можно обойтись без нее, но тогда диагностика будет выдаваться только
// при вызове соответствующих функций CValue
template<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
Оценка:
Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>Ошибки в комментариях.

ЮЖ>Так должно компилироваться, но ошибки при инстанцировании для типов, для которых специализаци отсутствуют будут диагностироваться на этапе линковки.
Это то, что надо. Спасибо! На работе залогинюсь, оценочку поставлю
Re[3]: Обязательная специализация классов
От: Кодт Россия  
Дата: 22.08.09 09:14
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Юрий Жмеренецкий, Вы писали:

ЮЖ>>Нужно переписать без них и все должно получиться.
А>Те же самые ошибки.

Можно не переписывать, а использовать правильным способом.
В реализации вместо STDMETHOD(...) писать STDMETHODIMP ..., а PURE просто убрать как неуместный. Метод-то не абстрактный, так зачем обманывать себя и компилятор?
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.