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

Войти
 
  Начало Форум WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  
  Просмотр сообщений
Страниц: 1 ... 37 38 [39]
571  Qt / Кладовая готовых решений / Re: Паттерн visitor для boost::any : Октябрь 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);
}
 

Вместо расчета суммы можно осуществить паковку данных с учетом последовательности прихода.
572  Qt / Кладовая готовых решений / Re: Паттерн visitor для boost::any : Октябрь 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.
573  Qt / Кладовая готовых решений / Re: Паттерн visitor для boost::any : Октябрь 22, 2015, 09:45
А вот насчет "реальных примеров" действительно туговато. С трудом выдавили "ячейки excel", что не кажется мне убедительным. Да и то сразу свалились в банальное if/else. Тогда почему бы не взять QVariant (где большого ума не надо). Но, насколько я понимаю, это стиль буста - возможно его решения гениальны, но он не дает классов которые можно просто "жрать" (как Qt).
Цитировать
В Qt хорошо, взял классик - и все работает
Улыбающийся

К сожалению QVariant абсолютно также плохо работает с пользовательскими типами - ни приведения, ни конвертации. Работает нормально только для базовых типов и типов Qt.
574  Qt / Кладовая готовых решений / Re: Паттерн visitor для boost::any : Октябрь 22, 2015, 09:24
Всё) Какие проблемы? Улыбающийся

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

Вопрос стоял по-другому. Есть шаблонный внешний код, который использует внутри посетителя to_double, он нас всем устраивает, но необходимо чтобы он работал и для пользовательского типа MyData.
С MyData можно выполнять любые определения и специализации, а вот внешний код или посетителя менять нельзя. Предположим, что посетителя нельзя подменить и через параметры шаблона.
Вопрос, есть ли способ определить такого посетителя to_double?
575  Qt / Кладовая готовых решений / Re: Паттерн visitor для boost::any : Октябрь 21, 2015, 14:43
Цитировать
Если заранее не известны возможные типы, то и в этом паттерне исчезает всякий смысл. Ведь когда мы проходимся по коллекции, мы уже должны знать как нам поступать с тем или иным объектом.

В данном случае в самом паттерне смысл тот же, просто такая реализация уже не подходит. Представьте ситуацию, что есть сторонняя библиотека, в которой реализован алгоритм с использованием visitor, например, как в Вашем примере, но ее нельзя использовать для своего пользовательского типа MyData, даже если существует способ преобразовать MyData в double. Отсюда и желание иметь подобную реализацию без формирования априори всего перечня возможных типов. Хотя перечень типов на момент компиляции известен, но оооочень длинный.
576  Qt / Кладовая готовых решений / Re: Паттерн visitor для boost::any : Октябрь 21, 2015, 13:13
В начальном примере все возможные типы известны заранее и описаны с помощью

Код
C++ (Qt)
type_list<double, int, float,  std::string>
 

Предположим что заранее такого перечня не существует, тогда реализация могла бы выглядеть примерно так

Код
C++ (Qt)
template < typename _Type >
struct to_double_helper;
 
template <>
struct to_double_helper< double >
{
   static double execute ( const boost::any & value )
   {
       return boost::any_cast< double >( value );
   }
};
 
template <>
struct to_double_helper< std::string >
{
   static double execute ( const boost::any & value )
   {
       return std::stod( boost::any_cast< std::string >( value ) );
   }
};
 
double to_double ( const boost::any & value )
{
   if ( value.type() == typeid( double ) )
       return to_double_helper< double >::execute( value );
   if ( value.type() == typeid( std::string ) )
       return to_double_helper< std::string >::execute( value );
   //...
 
 
   return 0;
}
 
int main()
{
   std::list< boost::any > many = {123, 3.14, 5.6f, std::string("2.71")};
   double sum = 0.0;
 
   for ( const auto & x : many )
       sum += to_double( x );
 
   std::cout << sum << std::endl;
   return 0;
}
 

Можно заменить содержимое to_double на что-то вроде

Код
C++ (Qt)
typedef double ( *to_double_function )( const boost::any & );
 
to_double_function to_double_function_for_type ( const std::type_info & type )
{
   to_double_function result = to_double_function();
   //...
   return result;
}
 
double to_double ( const boost::any & value )
{
   return (*to_double_function_for_type( value.type() ) )( value );
}
 

но это требует определение соотношений (std::type_info, to_double_function) в run-time, на этапе выполнения.

Есть какие нибудь идеи чтобы тоже самое реализовать в compile-time, но без формирования предварительного перечня типов, а имея только специализации to_double_helper?
577  Qt / Кладовая готовых решений / Re: Паттерн visitor для boost::any : Октябрь 21, 2015, 12:24
Я как раз и хотел не абстрактный пример, а реальный. Не совсем понятно, в каких задачах у нас может появиться гетерогенная коллекция. Увы, не встречался с таким.

Например, вы реализуете приложение типа Excel. Заранее вы не можете определить какой тип данных пользователь введет в ячейку таблицы и как правильно с ним работать. Вот отсюда и появляются всякие гетерогенные контейнеры и т.п.
Вообще гетерогенность не такая уж и редкость.

Страниц: 1 ... 37 38 [39]

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