Russian Qt Forum
Ноябрь 22, 2024, 23:08 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2] 3 4   Вниз
  Печать  
Автор Тема: Паттерн visitor для boost::any  (Прочитано 26170 раз)
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #15 : Октябрь 22, 2015, 00:48 »

На самом деле, проблем я вижу как минимум 3...

1 - опять же, подразумевается, что std::complex<double> - это тип, известный на момент компиляции. Но, скажем, у нас есть система классов, "скрытая" в библиотеке. Наружу открыт лишь интерфейс базового класса. Каким образом обработать типы, неизвестные заранее?

2 - в примере перегружается оператор (), что абсолютно неочевидно. Почему () должен обозначать приведение к типу, заданному в параметре шаблона? Что скажет выражение вроде to_double() ? Это вызов конструктора по умолчанию? А вот и нет Улыбающийся

3 - это уже не C++. Это другой язык  В замешательстве
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #16 : Октябрь 22, 2015, 09:13 »

Но, скажем, у нас есть система классов, "скрытая" в библиотеке. Наружу открыт лишь интерфейс базового класса. Каким образом обработать типы, неизвестные заранее?
Давайте забудем про шаблоны. Покажите как вы обрабатываете неизвестные типы на старом добром С++. Улыбающийся

Что скажет выражение вроде to_double() ? Это вызов конструктора по умолчанию? А вот и нет Улыбающийся
А вот и да. Улыбающийся
Это создние объекта. А следующие скобки уже будут вызывать оператор ().

3 - это уже не C++. Это другой язык  В замешательстве
Почему, это компилируется компилятором С++? Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Октябрь 22, 2015, 09:18 »

1 - опять же, подразумевается, что std::complex<double> - это тип, известный на момент компиляции. Но, скажем, у нас есть система классов, "скрытая" в библиотеке. Наружу открыт лишь интерфейс базового класса. Каким образом обработать типы, неизвестные заранее?
Не думаю что это проблема, просто базовый класс позовет virtual, в крайнем случае тип-указатель

2 - в примере перегружается оператор (), что абсолютно неочевидно.
ДАААА, и это капитально затрудняет понимание.

А вот насчет "реальных примеров" действительно туговато. С трудом выдавили "ячейки excel", что не кажется мне убедительным. Да и то сразу свалились в банальное if/else. Тогда почему бы не взять QVariant (где большого ума не надо). Но, насколько я понимаю, это стиль буста - возможно его решения гениальны, но он не дает классов которые можно просто "жрать" (как Qt).
Цитировать
В Qt хорошо, взял классик - и все работает
Улыбающийся
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #18 : Октябрь 22, 2015, 09:24 »

Всё) Какие проблемы? Улыбающийся

В реализации совсем другого посетителя to_double_advance проблем никаких нет  Подмигивающий

Вопрос стоял по-другому. Есть шаблонный внешний код, который использует внутри посетителя to_double, он нас всем устраивает, но необходимо чтобы он работал и для пользовательского типа MyData.
С MyData можно выполнять любые определения и специализации, а вот внешний код или посетителя менять нельзя. Предположим, что посетителя нельзя подменить и через параметры шаблона.
Вопрос, есть ли способ определить такого посетителя to_double?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #19 : Октябрь 22, 2015, 09:40 »

Но, насколько я понимаю, это стиль буста - возможно его решения гениальны, но он не дает классов которые можно просто "жрать" (как Qt).
А что мы сейчас делаем с boost::any?  Строит глазки
Берем готовый и "жрем" как в Qt. А конкретные обработчики данных описываем сами, как и в Qt.
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #20 : Октябрь 22, 2015, 09:45 »

А вот насчет "реальных примеров" действительно туговато. С трудом выдавили "ячейки excel", что не кажется мне убедительным. Да и то сразу свалились в банальное if/else. Тогда почему бы не взять QVariant (где большого ума не надо). Но, насколько я понимаю, это стиль буста - возможно его решения гениальны, но он не дает классов которые можно просто "жрать" (как Qt).
Цитировать
В Qt хорошо, взял классик - и все работает
Улыбающийся

К сожалению QVariant абсолютно также плохо работает с пользовательскими типами - ни приведения, ни конвертации. Работает нормально только для базовых типов и типов Qt.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #21 : Октябрь 22, 2015, 09:48 »

Хорошо, вот есть у меня место с ужасными свитчами (даже с моей толерантностью). Когда-то я уже о нем рассказывал. Предельно упрощенно
Код
C++ (Qt)
struct CData {
int mType;
union {
  int mInt;
  float mFloat;
  bool mBool;
  ARGB mColor;
};
};
Заметим что типов больше чем членов union (int и float могут быть signed/unsigned). Есть контейнер таких CData и есть десяток (или больше) операций с этим контейнером. Увы, каждая - немаленький switch. Вроде бы напрашивается "any", но есть маааленькая проблемка - небольшая контекстность. Ну совсем чуть-чуть  Улыбающийся

Когда выполняется запись в поток (ну и соответственно чтение) булевские CData пакуются. То есть неск идущих подряд булевских CData записываются одним интом с взведенными битами. Конечно это глупейшая экономия неск байт, но это уже проникло в плагины и менять себе дороже.

Как будет выглядеть проход any/many с учетом этого?

Спасибо
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #22 : Октябрь 22, 2015, 10:16 »

Когда-то я уже о нем рассказывал.
И тогда же вам посоветовали переписать его на С++, переделав структуру в дерево классов, каждый из которых выполняет заданную операцию. Что позволило бы полностью уйти от switch и упростить процесс добавления операций, исключив типичные ошибки с добавлением обработки в один switch и забыванием добавить в другой. Но вы же не пишите на С++...
А boost::any здесь никаких принципиальных решений для вас не добавит.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #23 : Октябрь 22, 2015, 10:53 »

Пожалуй я неправ говоря что это единственная проблема. Вот еще (ну может и не проблема, но как сделать не знаю)

- допустим мы гордо отказались от явно сохраненного типа (поле mType) и козырно собрали все в tuple, типа "ничего лишнего", только сами int, float и др. Но что же делать если идентификатор типа ('SINT', 'UINT' и др) нам понадобился? А такая необходимость есть, напр для внешнего редактора ресурсов, и для записи/чтения.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #24 : Октябрь 22, 2015, 11:32 »

Цитировать
С MyData можно выполнять любые определения и специализации, а вот внешний код или посетителя менять нельзя.
Вот это утверждение входит в разрез с идиалогией визитёрства, на мой взгляд) Идея ведь в том, чтоб дать возможность при изменении задачи, просто подменять соответствующих визитёров)
И более того, когда у нас появляется новый тип (complex, как в примере) мы же должны каким-то образом сообщить визитёру как с ним работать? А если его (визитёра) нельзя менять? И если API какой либо библиотеки, использующей этот механизм, такую возможность перекрывает, то стоит задуматься(

Цитировать
Предположим, что посетителя нельзя подменить и через параметры шаблона. Вопрос, есть ли способ определить такого посетителя to_double?

Здесь, наверное,  нет.. Хотя если написать свой moc для этого, то..  Улыбающийся

« Последнее редактирование: Октябрь 22, 2015, 11:47 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #25 : Октябрь 22, 2015, 12:03 »

Цитировать
- допустим мы гордо отказались от явно сохраненного типа (поле mType) и козырно собрали все в tuple, типа "ничего лишнего", только сами int, float и др. Но что же делать если идентификатор типа ('SINT', 'UINT' и др) нам понадобился?
Ну и в чём проблема то? 
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #26 : Октябрь 22, 2015, 12:09 »

Цитировать
Вот это утверждение входит в разрез с идиалогией визитёрства, на мой взгляд) ...

Здесь я согласен, похоже рассматриваемые задачи просто не предусматривают возможности решения с помощью идеологии визитеров).

Цитировать
Пожалуй я неправ говоря что это единственная проблема. Вот еще (ну может и не проблема, но как сделать не знаю)

- допустим мы гордо отказались от явно сохраненного типа (поле mType) и козырно собрали все в tuple, типа "ничего лишнего", только сами int, float и др. Но что же делать если идентификатор типа ('SINT', 'UINT' и др) нам понадобился? А такая необходимость есть, напр для внешнего редактора ресурсов, и для записи/чтения.

Если все возможные типы известны заранее, то можно решить задачу и с помощью визитеров. Если необходимо решить задачу в общем виде, то могу прокомментировать свое текущее решение. Так уж получилось, что по роду своей деятельности работать с неизвестными наперед типами приходится постоянно.

1. Изначально имеется класс, например, boost::any.
2. В добавок к нему реализованы классы фабрик, которые умеют генерировать boost::any.
Код
C++ (Qt)
 
struct AbstractAnyFabric
{
   virtual ~AbstractAnyFabric () {}
   virtual boost::any make () = 0;
};
 
template < typename _Type >
struct AnyFabric : public AbstractAnyFabric
{
   virtual boost::any make ()
   {
       return boost::any( _Type() );
   }
};
 

3. Для каждого типа реализован вызов уникального экземпляра фабрики (singleton)

Код:
template < typename _Type >
const AbstractAnyFactory & any_factory ()
{
    static const AnyFactory< _Type > factory;
    return factory;
}

4. Реализован механизм регистрации фабрик к функциям, например, к

Код
C++ (Qt)
Result foo ( const boost::any & )
 

5. Реализован механизм регистрации отображения любого идентификатора в фабрику.

Механизмы регистрации работают в run-time и предусматривают вызов методов аля qRegisterMetaType.
Вот этот run-time мне как раз не нравится, а решение в compile-time не нашел.

Такая система позволяет легко зарегистрировать и в дальнейшем использовать любую функциональность с boost::any.

Рассмотрим, например, сериализацию. Для этой задачи необходимо зарегистрировать отображения:

 - typeid( _Type ) в AnyFactory< _Type >,
 - AnyFactory< _Type > в уникальный ключ типа,
 - уникальный ключ типа в AnyFactory< _Type >,
 - AnyFactory< _Type > в метод сериализации,
 - AnyFactory< _Type > в метод десериализации.

В момент сериализации:

 - для типа any находим фабрику,
 - для фабрики находим уникальный ключ и метод сериализации,
 - сохраняет ключ,
 - выполняем сериализацию содержимого any.

В момент десериализации:

 - зачитываем ключ,
 - для ключа находим фабрику,
 - через фабрику генерируем any
 - для фабрики находим метод десериализации,
 - выполняем десериализацию содержимого any.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #27 : Октябрь 22, 2015, 13:16 »

Если все возможные типы известны заранее, то можно решить задачу и с помощью визитеров.
У меня известны заранее

Если необходимо решить задачу в общем виде, то могу прокомментировать свое текущее решение. Так уж получилось, что по роду своей деятельности работать с неизвестными наперед типами приходится постоянно.
Не все, но примерно понял. Спасибо

Ну и в чём проблема то? 
Хорошо, делаем по образцу Вашего первого поста
Код
C++ (Qt)
struct to_TypeID : public any_visitor<uint, type_list<int, uint, float,  bool, ARGB>>
{
   uint operator()(const int &) const { return 'SINT'; }
   uint operator()(const uint &) const { return 'UINT'; }
   uint operator()(const float &) const { return 'REAL'; }
   uint operator()(const bool &) const { return 'BOOL'; }
   uint operator()(const ARGB &) const { return 'ARGB'; }
};
Такую городушку надо иметь на каждое действие (в данном случае это получить ID типа как число). Ну лады, надо так надо, пусть пока "выйгрыша" нет, потерпим. Но вот что делать с 2 моими типами которые в эту схему не вписались

- флот может быть любой ('REAL') или только положительный ('UREL')
- цвет может быть с альфой ('ARGB') или без ('CRGB')

Создавать для них классы? Конечно это несложно, но как-то неоднообразно выходит. Может тогда есть смысл оставить идентификатор типа как член класса?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #28 : Октябрь 22, 2015, 13:35 »

Цитировать
Создавать для них классы? Конечно это несложно, но как-то неоднообразно выходит.
Наоборот, это даст однообразность. Если необходимо обеспечивать различное поведение (обработку) для типов REAL и UREAL, ARGB и CRGB во многих ситуациях, то лучше сразу вначале выделить все разнородные классы. И работать уже однообразно (в категориях визитёра) с этим множеством.  

И, кстатии, если все типы уже известны заранее и не предполагается добавление новых, то  более уместен boost::variant.. 
« Последнее редактирование: Октябрь 22, 2015, 13:38 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #29 : Октябрь 23, 2015, 09:28 »

Хорошо, не хочу показаться навязчивым, но все же как с "маленькими исключениями"?
Когда выполняется запись в поток (ну и соответственно чтение) булевские CData пакуются. То есть неск идущих подряд булевских CData записываются одним интом с взведенными битами. Конечно это глупейшая экономия неск байт, но это уже проникло в плагины и менять себе дороже.

Как будет выглядеть проход any/many с учетом этого?
А то часто бывает что конструкция-то красивая, а маленький шажок влево-вправо обходится безумно дорого. Здесь в поток пишутся только сами значения, предполагается что читающему известны типы и порядок.

Спасибо
Записан
Страниц: 1 [2] 3 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.246 секунд. Запросов: 23.