Russian Qt Forum

Программирование => С/C++ => Тема начата: Igors от Август 30, 2016, 09:04



Название: MetaData (Lite)
Отправлено: Igors от Август 30, 2016, 09:04
Добрый день

Набегают новые фичи, к базовой структуре постоянно добавляются новые члены данных нужные для какого-то конкретного случая. Нормально сделать мапу чтобы по ключу добавлять/брать такие данные (вместо того чтобы менять структуру всякий раз). По смыслу QVariantMap подходит, но связываться с обильным QVariant не хочется, да и в данных файлах Qt нет, тащить его из-за такой мелочи не резон. Тогда как иначе? В принципе пока устраивает даже
Код
C++ (Qt)
std::map<int, void *>
Т.к. данные POD. Но уж слишком вызывающе - С приведения, удаление void. Как бы это сделать аккуратнее и чтобы было скромно, компактно?

Спасибо


Название: Re: MetaData (Lite)
Отправлено: Racheengel от Август 30, 2016, 10:19
сделать свой union ?


Название: Re: MetaData (Lite)
Отправлено: ssoft от Август 30, 2016, 10:42
Лучше сделать по типу boost::any, там кода не так уж и много, зато не торчит никакой void *

Если кратко, то заводим AbstractHolder, для каждого типа от него порождаем Holder< _Type >. Строим Variant/Any поверх указателя на Holder.

Простейший случай выглядит как-то так

Код
C++ (Qt)
   struct AbstractHolder;
   std::shared_ptr< AbstractHolder > SharedHolder;
 
   struct AbstractHolder
   {
   public:
       virtual ~AbstractHolder () {}
       virtual const char * type () const = 0;
       virtual SharedHolder clone () const = 0;
   };
 
   template < typename _Value >
   struct Holder
       : public AbstractHolder
   {
   public:
       typedef Holder< _Value > ThisType;
 
   public:
       _Value m_value;
 
   public:
       Holder () : m_value() {}
       template < typename _Type >
       Holder ( const _Type & value ): m_value( value ) {}
       virtual const char * type () const ( typeid( _Type >().name(); }
       virtual SharedHolder clone () const { return SharedHolder( new ThisType( m_value ); }
   };
 
   class Variant
   {
       SharedHolder m_holder;
 
   public:
       Variant () : m_holder() {}
       Variant ( const Variant & other ) : m_holder() { *this = other; }
       Variant & operator = ( const Variant & other ) { m_holder = other.m_holder ? other.m_holder->clone() : SharedHolder(); }
 
       template < typename _Type >
       bool isA () const { return m_holder ? typeid( _Type ).name() == m_holder.type() : false; }
       template < typename _Type >
       const _Type value () const { return isA< _Type >() ? static_cast< const Holder< _Type > * >( &*m_holder )->m_value : _Type() }
       template < typename _Type >
       static Variant fromValue ( const _Type & value ) { Variant result; result.m_holder = SharedHolder( new Holder< _Type >( value ) ); }
   };
 


Название: Re: MetaData (Lite)
Отправлено: Old от Август 30, 2016, 10:47
Лучше сделать по типу boost::any, там кода не так уж и много, зато не торчит никакой void *
Да уже даже есть готовое решение, горячО обсужденное. :)
http://www.prog.org.ru/topic_28407_0.html


Название: Re: MetaData (Lite)
Отправлено: _Bers от Август 30, 2016, 22:51
Добрый день

Набегают новые фичи, к базовой структуре постоянно добавляются новые члены данных нужные для какого-то конкретного случая. Нормально сделать мапу чтобы по ключу добавлять/брать такие данные (вместо того чтобы менять структуру всякий раз). По смыслу QVariantMap подходит, но связываться с обильным QVariant не хочется, да и в данных файлах Qt нет, тащить его из-за такой мелочи не резон. Тогда как иначе? В принципе пока устраивает даже
Код
C++ (Qt)
std::map<int, void *>
Т.к. данные POD. Но уж слишком вызывающе - С приведения, удаление void. Как бы это сделать аккуратнее и чтобы было скромно, компактно?

Спасибо


сначала - void*

затем, если будет актуально, время и желание - Arg.
это - "умный void*"
c возможностью проверки типизации и квалификатора const времени выполнения.

суть такая: в зависимости от опций компиляции Arg сворачивается в тот же void*,
или валидирует assert`ами.
или валидирует exception`ами.



Название: Re: MetaData (Lite)
Отправлено: Igors от Август 31, 2016, 15:20
Если кратко, то заводим AbstractHolder, для каждого типа от него порождаем Holder< _Type >. Строим Variant/Any поверх указателя на Holder.

Простейший случай выглядит как-то так
Я пошел др путем (аттач)  :), но получилось похоже - тоже holder, тоже выртуальная база  и наследуемый от нее темплейтник. Да, эта конструкция делает все что требуется и неплохо расширяема, но колоссальный минус - всякое отсутствие желанной простоты  :'( Вот если таких классов мало, они хорошо известны, "узаконены" в проекте и под рукой online help - тогда да, они полезны. А иначе они не стоят того чтобы с ними разбираться.

сделать свой union ?
И в деструкторе свитчеваться?  И на get/set проверять тип сохраненный явно? Не, ну так я давно умею :)

затем, если будет актуально, время и желание - Arg.
это - "умный void*"
c возможностью проверки типизации и квалификатора const времени выполнения.
Цитировать
Будете у нас на Колыме...
Нет уж!! Лучше Вы у нам!
:)


Название: Re: MetaData (Lite)
Отправлено: Racheengel от Август 31, 2016, 15:43
union позволяет избежать дополнительных аллокаций памяти и проверок рантайма (что бьёт по производительности). А насчет свитчей в деструкторе "моя не поняла". Достаточно юниона + одного флага, который хранит тип данных (я ж так понял, что все типы - должны быть чисто POD?)


Название: Re: MetaData (Lite)
Отправлено: Igors от Сентябрь 01, 2016, 06:43
union позволяет избежать дополнительных аллокаций памяти и проверок рантайма (что бьёт по производительности). А насчет свитчей в деструкторе "моя не поняла". Достаточно юниона + одного флага, который хранит тип данных (я ж так понял, что все типы - должны быть чисто POD?)
Пока POD, дальше хз
Код
C++ (Qt)
struct MyU {
int mTypeID;
union {
  MyStruct1 s1;
  MyStruct2 s2;
  ...
};
};
Вот появится MyStruct3 всего лишь имеющий конструктор - и все, приплыли. Поэтому придется так
Код
C++ (Qt)
struct MyU {
int mTypeID;
union {
  MyStruct1 * s1;
  MyStruct2 * s2;
  ...
};
};
Но тогда вылазят саитчи. В обоих случаях неприятно что все хедеры (где описаны MyStruct xxx) должны присутствовать, MyU "обо всех знает", а это хреново.