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

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

Страниц: 1 2 [3] 4   Вниз
  Печать  
Автор Тема: Паттерн visitor для boost::any  (Прочитано 25291 раз)
ssoft
Программист
*****
Offline Offline

Сообщений: 579


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

Так тут можно так поступить. Правда не совсем визитер, но суть та же.

Код
C++ (Qt)
typedef type_list< double, int, std::string, float > list_of_types;
 
struct cals_sum : public any_visitor< double, list_of_types >
{
   double m_sum;
 
   cals_sum () : m_sum() {}
 
   double operator()( const std::string & str ) { return m_sum += std::stod(str); }
   template <class T>
   double operator()( const T & val ) { return m_sum += double( val ); }
};
 
 
struct to_string : public any_visitor< std::string, list_of_types >
{
   std::string operator()( const std::string & str ) const { return str; }
 
   template <class T>
   std::string operator()(const T & val) const { return std::to_string(val); }
};
 
int main()
{
   std::list< boost::any > many = {123, 3.14, 5.6f, std::string("2.71")};
 
   cals_sum visitor;
   for ( const auto & x : many )
       apply_any_visitor( visitor, x );
 
   std::cout << visitor.m_sum << std::endl;
   return 0;
}
 

Ну плюс модифицировать apply часть для возможности работы с неконстантными визитерами.

Код
C++ (Qt)
template <class Visitor, class TypeList>
struct any_cast_helper
{
   static typename Visitor::result_type get(const boost::any & any, Visitor & visitor)
   {
       if (any.type() == typeid(typename TypeList::first_type))
           return visitor(boost::any_cast<typename TypeList::first_type >(any));
 
       return any_cast_helper<Visitor, typename TypeList::next_type_list>::get(any, visitor);
   }
   static typename Visitor::result_type get(const boost::any & any, const Visitor & visitor)
   {
       if (any.type() == typeid(typename TypeList::first_type))
           return visitor(boost::any_cast<typename TypeList::first_type>(any));
 
       return any_cast_helper<Visitor, typename TypeList::next_type_list>::get(any, visitor);
   }
};
 
 
template <class Visitor>
struct any_cast_helper<Visitor, null_type>
{
   static typename Visitor::result_type get(const boost::any &, Visitor &) throw(std::bad_cast)
   {
       throw std::bad_cast();
   }
   static typename Visitor::result_type get(const boost::any &, const Visitor &) throw(std::bad_cast)
   {
       throw std::bad_cast();
   }
};
 
 
template <class Visitor>
typename Visitor::result_type apply_any_visitor(const Visitor & visitor, const boost::any & any)
{
   return any_cast_helper<Visitor, typename Visitor::type_list>::get(any, visitor);
}
 
template <class Visitor>
typename Visitor::result_type apply_any_visitor( Visitor & visitor, const boost::any & any)
{
   return any_cast_helper<Visitor, typename Visitor::type_list>::get(any, visitor);
}
 

Вместо расчета суммы можно осуществить паковку данных с учетом последовательности прихода.
« Последнее редактирование: Октябрь 23, 2015, 10:21 от ssoft » Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



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

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

Пишите визитёра для записи в поток:
Код
C++ (Qt)
template <class Stream>
struct serialize : public any_visitor<void, type_list<int, uint, float,  bool, ARGB>>
{
   serialize(Stream & out) : m_out(out) {}
 
   template <class T>
   void operator()(const T & val) { m_out << val; }
 
private:
   Stream & m_out;
};
 

Цитировать
но все же как с "маленькими исключениями"?
А этим по логике должен заниматься Stream. Научите его паковать подряд идущие bool в int..
Записан

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

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

Сообщений: 4349



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

А этим по логике должен заниматься Stream. Научите его паковать подряд идущие bool в int..
Или используйте внешний серилизатор, который умеет это делать.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



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

Цитировать
Ну плюс модифицировать apply часть для возможности работы с неконстантными визитерами.

Да, это нужная фича, спасибо)  

Или может тогда уж просто по значению его передавать
Код
C++ (Qt)
static typename Visitor::result_type get(const boost::any & any, Visitor visitor)
 
Визитёры, они ведь не слишком то уж жирные  Улыбающийся
Записан

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

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

Сообщений: 11445


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

А этим по логике должен заниматься Stream. Научите его паковать подряд идущие bool в int..
А откуда он может знать что это bool? Оно пишется как и int. Наследоваться от stream - ну явно "не то". В общем, я так и знал: вот парИть по концепциям - то да, а со всякими мелочами пусть дедушка сидит. Это же так "непринципиально"  Улыбающийся
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



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

В общем, я так и знал: вот парИть по концепциям - то да, а со всякими мелочами пусть дедушка сидит.
Ну кто-то и это должен делать, если с концепциями не получается. Улыбающийся
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



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

Цитировать
А откуда он может знать что это bool? Оно пишется как и int. Наследоваться от stream - ну явно "не то".
Не нужно наследоваться.. Как сказал Old достаточно внешнего сериализатора, который это умеет. Самый простейший вариант в пару строк:
Код
C++ (Qt)
class serializator
{
public:
   serializator(std::ofstream & out) : m_out(out) {}
 
   template <class T>
   friend serializator & operator<<(serializator &, const T &);
 
   friend serializator & operator<<(serializator &, bool);
 
private:
   int bool_packet;
   std::ofstream & m_out;
};
 
А в операторах << реализуете упаковку булов в bool_paket и т.д. и т.п..
Записан

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

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

Сообщений: 11445


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

Самый простейший вариант в пару строк:
Та где ж "пару" если только хедер уже десяток, да и то неполный - напр забыли вытолкнуть последний набор флагов. Создали класс для такой мелочи, завязались на ofstream - нуу...  Плачущий

Опять-таки, где "выйгрыш"? Писали этажерку switch для каждого действия, теперь для каждого действия класс и в нем опять расписываем. Да, вот если действие повторяется - тогда задействуем уже готовый apply, а ветку switch придется заново рисовать. Ну навскидку я таких повторов не помню.

Ладно, все равно спасибо, хорошая получилась тема
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



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

Писали этажерку switch для каждого действия, теперь для каждого действия класс и в нем опять расписываем. Да, вот если действие повторяется - тогда задействуем уже готовый apply, а ветку switch придется заново рисовать. Ну навскидку я таких повторов не помню.
Вообще не одного попадания.

Ладно, все равно спасибо, хорошая получилась тема
Уже по моему четвертая про длинные switch. Улыбающийся
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



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

Цитировать
Уже по моему четвертая про длинные switch.  Улыбающийся
И что-то мне подсказывает, что ещё далеко не последняя  Улыбающийся
Записан

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

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

Сообщений: 11445


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

Кстати вот такое наблюдение. Часто приходилось читать что, мол, класс - это "сущность", понятие фундаментальное и все такое. Но с бустовским подходом это совсем не так. Здесь класс - нечто чисто техническое, типа оператора, никакой "сущностью" он не является. Если видим только сам класс (без его использования) - вряд ли возможно понять зачем он. В общем "узурпировали"  Улыбающийся
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



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

Кстати вот такое наблюдение. Часто приходилось читать что, мол, класс - это "сущность", понятие фундаментальное и все такое. Но с бустовским подходом это совсем не так. Здесь класс - нечто чисто техническое, типа оператора, никакой "сущностью" он не является. Если видим только сам класс (без его использования) - вряд ли возможно понять зачем он. В общем "узурпировали"  Улыбающийся
Это не так. Функтор это такая же сущность, выполняющая строго свою задачу. И функторы применяются не только в бусте, но и в огромном количестве других библиотек и программ, не обязательно плюсовых.
Хотите посмотреть на функторы в Qt, взгляните на файл qsortfilterproxymodel.cpp, они там в начале, и скажите, если смотреть только на них, вам понятно что они делают?
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



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

Добавил визитёру возможность изменять содержимое boost::any. Думаю, это полезная фича)
Т.е. сейчас можно делать так:
Код
C++ (Qt)
struct editor : public any_visitor<void, type_list<int, double, std::string>>
{
   void operator()(std::string & s) { s += " Qt5"; }
 
   void operator()(int & i) { i += 100500; }
 
   void operator()(double & d) { d = 3.14159; }
};
 
struct printer : public any_visitor<void, type_list<int, double, std::string>>
{
   template <class T>
   void operator()(const T & val) const { std::cout << val << std::endl; }
};
 
int main()
{
   std::list<boost::any> many = {13, 1.34834657, std::string("hello")};
 
   std::cout << "before:" << std::endl;
   for (auto & x : many)
       apply_any_visitor(printer(), x);
 
   for (auto & x : many)
       apply_any_visitor(editor(), x); // Editor изменяет значения элементов.
 
   std::cout << "after:" << std::endl;
   for (auto & x : many)
       apply_any_visitor(printer(), x);
 
   return 0;
}
 
Записан

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

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

Сообщений: 2679


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


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

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

Конечно, иногда лучше так, чем лопатить все заново... но имхо это из разряда костыльных паттернов, не?
Записан

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 не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



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

Цитировать
но имхо это из разряда костыльных паттернов, не?
Нет конечно) Визитёр это как раз пример очень гибкого расширяемого решения, в отличии бесконечных свитчей намертво привязанных к коду)   
Записан

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

Arch Linux Plasma 5
Страниц: 1 2 [3] 4   Вверх
  Печать  
 
Перейти в:  


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