Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Шаблоны - и union


Автор: Lazin 27.12.2007, 14:50
Я сейчас работаю над одной проблемой, которая вызывает некоторые затруднения, вот ее упрощенный аналог:
есть такая структура 
Код

struct VALUE
{
 union {
  double dbl;
  long i64;
 };
 byte type;
};
 это вариантный тип данных, что-бы узнать что она содержит нужно проверить поле type
.
она должна обрабатываться методом
Код

template<Format, Packer>
void Pack(VALUE & v)
{
 Format::Process(v);
 Packer::Pack(v);
}


шаблонные параметры: Format - преобразует число содержащееся в структуре по некоторому правилу, реализации Format исходят из того что в структуре содержится число определенного типа (поле type не проверяется)
Код

class DoubleFormat1
{
public:
  static void Process(VALUE& v)
  { сделать что то с v.dbl %)
  }
};


Код

class IntFormat1
{
public:
  static void Process(VALUE& v)
  { сделать что то с v.i64
  }
};


в общем эти классы нужны для преобразования значения VALUE? и их может быть много

Packer - класс обеспечивающий сжатие данных, он то-же работает с VALUE как со значением определенного типа (предварительно структура должна быть обработана соответствующим методом Format)
Код

class IntPacker1
{
public:
  static void Pack(VALUE& v)
  { сделать что то с v.i64 
  }
};


в общем я этим хочу добится 2х вещей, что-бы не проверять каждый раз тип структуры VALUE, так как он известен на этапе компиляции, и комбинировать разные методы обработки VALUE
короче я хочу делать так:
Код

Pack<IntFormat1, IntPacker1>(v);
Pack<IntFormat2, IntPacker3>(v);
Pack<DoubleFormat4, DoublePacker1>(v);

.....
проблема в том что теперь возможен и такой вариант
Код

Pack<IntFormat1, DoublePacker1>(v);

и тд
что в моем случае недопустимо
можно в принципе использовать STATIC_ASSERT что-бы на стадии компиляции запрещать невозможные комбинации, но я не могу отделаться от одной мысли: 
если у меня возникла такая ситуация, значит декомпозиция задачи выполнена не верно, я где-то допустил ошибку в проектировании, что вы думаете по этому поводу?

Автор: archimed7592 27.12.2007, 16:43
Код

struct ToDouble
    :    public std::unary_function< VALUE &, double & >
{
    double &operator()(VALUE &x) const
    { return x.dbl; }
};
struct ToI64
    :    public std::unary_function< VALUE &, long & >
{
    long &operator()(VALUE &x) const
    { return x.i64; }
};

template<Converter, Format, Packer>
void Pack(VALUE & v)
{
 Converter c;
 Converter::result_type r = c(v);
 Format::Process(r);
 Packer::Pack(r);
}

Fromatter и Packer соответственно переделать под более строгие типы(double и long).

Автор: Lazin 28.12.2007, 09:26
archimed7592, твой вариант:
+ делает невозможным лишние комбинации
- лишний шаблонный параметр
-----------------------------
мне кажется что можно сделать проще, но как - пока не скажу))

Автор: archimed7592 28.12.2007, 13:03
Цитата(Lazin @  28.12.2007,  09:26 Найти цитируемый пост)
мне кажется что можно сделать проще, но как - пока не скажу)) 

Можно: добавить к VALUE неявное преобразование как к double, так и к long, после чего форматеры и пакеры писать так, чтобы принимали аргумент нужного типа(а не VALUE).
Только, лично мне кажется наоборот, что с третьим параметром кошернее smile.

Добавлено через 1 минуту и 1 секунду
Ещё можно сделать так, чтобы этот третий параметр шёл аргументом и вычислять его автоматически - тогда и параметр будет и указывать его не нужно будет smile.

Автор: baldina 28.12.2007, 18:47
archimed7592,
Цитата

с третьим параметром кошернее 

в принципе - да, но лучше его неявно использовать, учтя, что он есть свойство Format и Packer: сделаем его параметром этих классов

Lazin, посмотри:
Код

template <typename T> 
struct PackTraits {
  // нет преобразования PackTraits<double> <-> PackTraits<int>
};

template <typename T> struct Format {
  typedef PackTraits<T> type_traits;
};

template <typename T> struct Packer {
  typedef PackTraits<T> type_traits;
};

template <typename F, typename P> 
class Pack {
  // не должно компилиться если F и P параметризованы разными типами
  void _check_type_traits (const typename F::type_traits& f=F::type_traits()) { typename P::type_traits p(f); } 
public:
  Pack () { _check_type_traits(); }
};

class IntFormat2 : public Format<int> {};
class IntPacker3 : public Packer<int> {};
class DoubleFormat4 : public Format<double> {};
class DoublePacker1 : public Packer<double> {};

Pack<IntFormat2, IntPacker3> v;
Pack<DoubleFormat4, DoublePacker1> v1;
Pack<IntFormat2, DoublePacker1> v2; // error


Добавлено @ 18:54
можно даже так, что бы в конструкторах Pack не думать о проверках:
Код

template <typename F, typename P> 
struct Pack_Helper {
  Pack_Helper () { typename P::type_traits (typename F::type_traits()); }
};

template <typename F, typename P> 
class Pack : public Pack_Helper <F,P> {
};

Автор: baldina 28.12.2007, 19:02
Lazin,
Цитата

но я не могу отделаться от одной мысли

имхо все у тебя с дизайном правильно, просто чуть не дотянул до реализации
 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)