Variant по mpl types sequences как член класса - как сделать?
От: LowCoder  
Дата: 03.02.14 12:16
Оценка:
Привет всем!

Посоветуйте плз. решение. Хочу иметь переменную класса variant по заранее определенной последовательности типов. А затем в main вызвать метод, который вызывает метод каждого объекта, который имеет тип определенный в последовательности типов .

Сейчас поясню.


struct worker1
{
   void init()
   {
      std::cout << "Worker1 init called" << std::endl;
   }
};

struct worker2
{
   void init()
   {
      std::cout << "Worker2 init called" << std::endl;
   }
};

typedef mpl::vector< worker1, worker2> workers;

template< typename U> struct process3
{
   process3()
   {
      factory();
   }

   struct factoryrun
   {
      template< typename T > void operator()(T& x)
      {
         std::cout << "Factory entry" << std::endl;
         std::cout << "Type is = " << typeid( T ).name() << std::endl;

         m_t3.push_back( x ); // FAIL!!! :(( Doesn't work
      }
   };

   struct runinit
   {
      template<typename T> void operator()(T& x)
      {
         x.init();
      }
   };

   void init()
   {
      mpl::for_each<U>( runinit() );
   }

   void factory()
   {
      std::cout << "Factory start" << std::endl;
      mpl::for_each<U>( factoryrun() );
   }

   typedef typename boost::make_variant_over< U >::type types; // FAIL!!! Doesn't work because I need to have variant<worker1, worker2> but not variant<workers>
   static std::vector< boost::variant<types> > m_t;
};

template<typename K> std::vector< boost::variant<K> > process<K>::m_t;

int main() {
   process<workers> prs;
   // Here should be called init() for worker1 and worker2   
   prs.init();
   return 0;
}
Re: Variant по mpl types sequences как член класса - как сделать?
От: Abyx Россия  
Дата: 03.02.14 12:40
Оценка:
Здравствуйте, LowCoder,

variadic templates должны помочь. mpl не очень-то и нужно.
In Zen We Trust
Re: Variant по mpl types sequences как член класса - как сделать?
От: Evgeny.Panasyuk Россия  
Дата: 03.02.14 13:07
Оценка:
Здравствуйте, LowCoder, Вы писали:

Тут очепятки:
LC>
LC>         m_t3.push_back( x ); // FAIL!!! :(( Doesn't work
LC>
LC>template<typename K> std::vector< boost::variant<K> > process<K>::m_t;
LC>


Вот этот вариант компилируется.

P.S. дополнительно можешь проверить BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT
Re: Variant по mpl types sequences как член класса - как сделать?
От: Warturtle  
Дата: 03.02.14 13:12
Оценка:
Здравствуйте, LowCoder, Вы писали:

Пример не компилирвется по другим причинам, но один variant кажется лишним (см. выделенное ниже)
LC>...

LC>
LC>...

LC>typedef mpl::vector< worker1, worker2> workers;

LC>template< typename U> struct process3
LC>{
LC>   process3()
LC>   {
LC>      factory();
LC>   }

LC>   struct factoryrun
LC>   {
LC>      template< typename T > void operator()(T& x)
LC>      {
LC>         std::cout << "Factory entry" << std::endl;
LC>         std::cout << "Type is = " << typeid( T ).name() << std::endl;

LC>         m_t3.push_back( x ); // FAIL!!! :(( Doesn't work
LC>      }
LC>   };

LC>   ...

LC>   typedef typename boost::make_variant_over< U >::type types; // FAIL!!! Doesn't work because I need to have variant<worker1, worker2> but not variant<workers>
LC>   //static std::vector< boost::variant<types> > m_t;
LC>   static std::vector< types > m_t; // По кр мере должно быть как-то так
LC>};

LC>template<typename K> std::vector< boost::variant<K> > process<K>::m_t;

LC>...
LC>
Re[2]: Variant по mpl types sequences как член класса - как сделать?
От: LowCoder  
Дата: 03.02.14 13:15
Оценка:
Здравствуйте, Warturtle, Вы писали:

W>Здравствуйте, LowCoder, Вы писали:


W>Пример не компилирвется по другим причинам, но один variant кажется лишним (см. выделенное ниже)

LC>>...

LC>>
LC>>...

LC>>typedef mpl::vector< worker1, worker2> workers;

LC>>   static std::vector< types > m_t; // По кр мере должно быть как-то так
LC>>};

LC>>template<typename K> std::vector< boost::variant<K> > process<K>::m_t;

LC>>...
LC>>



Так к сожалению не работает — я пробовал. m_t3 это просто опечатка — в коде все ок. Variadic мне к сожалению не подходит — требование проекта.
Re[3]: Variant по mpl types sequences как член класса - как сделать?
От: Warturtle  
Дата: 03.02.14 13:23
Оценка:
Здравствуйте, LowCoder, Вы писали:

LC>Здравствуйте, Warturtle, Вы писали:


W>>Здравствуйте, LowCoder, Вы писали:


W>>Пример не компилирвется по другим причинам, но один variant кажется лишним (см. выделенное ниже)

LC>>>...

LC>>>
LC>>>...

LC>>>typedef mpl::vector< worker1, worker2> workers;

LC>>>   static std::vector< types > m_t; // По кр мере должно быть как-то так
LC>>>};

LC>>>template<typename K> std::vector< boost::variant<K> > process<K>::m_t;

LC>>>...
LC>>>



LC>Так к сожалению не работает — я пробовал. m_t3 это просто опечатка — в коде все ок. Variadic мне к сожалению не подходит — требование проекта.



#include <vector>
#include <iostream>
#include "boost/config.hpp"
#include "boost/variant/variant.hpp"
#include "boost/mpl/vector.hpp"
#include "boost/mpl/for_each.hpp"
namespace mpl = boost::mpl;

struct worker1
{
   void init()
   {
      std::cout << "Worker1 init called" << std::endl;
   }
};

struct worker2
{
   void init()
   {
      std::cout << "Worker2 init called" << std::endl;
   }
};

typedef mpl::vector< worker1, worker2 > workers;

template< typename U> struct process
{
   process()
   {
      factory();
   }

   struct factoryrun
   {
      template< typename T> void operator()(T& x)
      {
         std::cout << "Factory entry" << std::endl;
         std::cout << "Type is = " << typeid( T ).name() << std::endl;

         m_t.push_back( x );
      }
   };

   struct runinit
   {
      template<typename T> void operator()(T& x)
      {
         x.init();
      }
   };

   void init()
   {
      mpl::for_each<U>( runinit() );
   }

   void factory()
   {
      std::cout << "Factory start" << std::endl;
      mpl::for_each<U>( factoryrun() );
   }

   typedef typename boost::make_variant_over< U >::type types;
   static std::vector< types > m_t;
};

template<typename K> std::vector< typename process<K>::types > process<K>::m_t;

int main() {
   process<workers> prs;
   
   // Here should be called init() for worker1 and worker2   
   prs.init();
   return 0;
}
Re[2]: Variant по mpl types sequences как член класса - как сделать?
От: LowCoder  
Дата: 03.02.14 13:30
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, LowCoder, Вы писали:


EP>Тут очепятки:

LC>>
LC>>         m_t3.push_back( x ); // FAIL!!! :(( Doesn't work
LC>>
LC>>template<typename K> std::vector< boost::variant<K> > process<K>::m_t;
LC>>


EP>Вот этот вариант компилируется.


EP>P.S. дополнительно можешь проверить BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT



Огромное спасибо!

Проблема решена.
Re[3]: Variant по mpl types sequences как член класса - как сделать?
От: LowCoder  
Дата: 03.02.14 13:54
Оценка:
Кстати вопрос напоследок — а можно было бы эту задачу решить через boost::recursive_variant или make_recursive_variant_over
Re: Variant по mpl types sequences как член класса - как сделать?
От: LowCoder  
Дата: 03.02.14 17:40
Оценка:
Я очень извиняюсь но код был не совсем корректный. Дело в том что на каждый вызов функций init, run, stop создаются все новые объекты worker1 worker2 те внутренняя переменная m_t3 не вызывается. А вот и правильное окончательное и бесповоротное решение:


///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
struct worker1
{
   worker1()
   {
      std::cout << "Worker1 ctor" << std::endl;
   }

   void init()
   {
      std::cout << "Worker1 init called. Object address [" << this << "]" << std::endl;
   }

   void run()
   {
      std::cout << "Worker1 run called. Object address [" << this << "]" << std::endl;
   }

   void stop()
   {
      std::cout << "Worker1 stop called. Object address [" << this << "]" << std::endl;
   }
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
struct worker2
{
   worker2()
   {
      std::cout << "Worker2 ctor" << std::endl;
   }

   void init()
   {
      std::cout << "Worker2 init called. Object address [" << this << "]" << std::endl;
   }

   void run()
   {
      std::cout << "Worker2 run called. Object address [" << this << "]" << std::endl;
   }

   void stop()
   {
      std::cout << "Worker2 stop called. Object address [" << this << "]" << std::endl;
   }

};

typedef mpl::vector< worker1, worker2 > workers;

///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
template< typename U> struct process3
{
   process3()
   {
      factory();
   }

   struct factoryrun
   {
      template< typename T > void operator()(T& x)
      {
         std::cout << "Factory entry" << std::endl;
         std::cout << "Type is = " << typeid( T ).name() << std::endl;

         m_t3.push_back( x );
      }
   };

   void init()
   {
      static init_visitor vis;
      std::for_each( m_t3.begin(), m_t3.end(), boost::apply_visitor( vis ) );
   }

   void run()
   {
      static run_visitor vis;
      std::for_each( m_t3.begin(), m_t3.end(), boost::apply_visitor( vis ) );
   }

   void stop()
   {
      static stop_visitor vis;
      std::for_each( m_t3.begin(), m_t3.end(), boost::apply_visitor( vis ) );
   }

   typedef typename boost::make_variant_over< U >::type types;
   typedef std::vector<types> Vector; // Make typedef to simplify
   static Vector m_t3;

   struct init_visitor: public boost::static_visitor<>
   {
      template <typename T>
      void operator()( T& x )
      {
         std::cout << "Init visitor type=" << typeid(x).name() << std::endl;
         x.init();
       }
   };

   struct run_visitor: public boost::static_visitor<>
   {
     template <typename T>
     void operator()( T& x )
     {
        std::cout << "Run visitor type=" << typeid(x).name() << std::endl;
        x.run();
      }
   };

   struct stop_visitor: public boost::static_visitor<>
   {
     template <typename T>
     void operator()( T& x )
     {
        std::cout << "Stop visitor type=" << typeid(x).name() << std::endl;
        x.stop();
      }
   };
};

template<typename K> typename process3<K>::Vector process3<K>::m_t3;

int main() {
   process3<workers> prs3;
   prs3.init();
   prs3.run();
   prs3.stop();
   return 0;
}


Вывод чудо-проги


Factory start
Worker1 ctor
Factory entry
Type is = 7worker1
Worker2 ctor
Factory entry
Type is = 7worker2
Init visitor type=7worker1
Worker1 init called. Object address [0x21bf038]
Init visitor type=7worker2
Worker2 init called. Object address [0x21bf048]
Run visitor type=7worker1
Worker1 run called. Object address [0x21bf038]
Run visitor type=7worker2
Worker2 run called. Object address [0x21bf048]
Stop visitor type=7worker1
Worker1 stop called. Object address [0x21bf038]
Stop visitor type=7worker2
Worker2 stop called. Object address [0x21bf048]



те конструкторы воркеров вызываются только один раз.
Re[2]: Variant по mpl types sequences как член класса - как сделать?
От: Evgeny.Panasyuk Россия  
Дата: 03.02.14 18:03
Оценка:
Здравствуйте, LowCoder, Вы писали:

LC>А вот и правильное окончательное и бесповоротное решение:

LC>
LC>   void init()
LC>   {
LC>      static init_visitor vis;
LC>      std::for_each( m_t3.begin(), m_t3.end(), boost::apply_visitor( vis ) );
LC>   }
LC>   void run()
LC>   {
LC>      static run_visitor vis;
LC>      std::for_each( m_t3.begin(), m_t3.end(), boost::apply_visitor( vis ) );
LC>   }
LC>   void stop()
LC>   {
LC>      static stop_visitor vis;
LC>      std::for_each( m_t3.begin(), m_t3.end(), boost::apply_visitor( vis ) );
LC>   }
LC>


Тут можно убрать дублирование, вынеся общую часть в отдельное место.

LC>Вывод чудо-проги


Если нужна скорость, и не важен порядок элементов в векторе, то вместо вектора вариантов можно использовать отдельный вектор на каждый тип. Это убирает dynanic-dispatch при заходе в каждый элемент, плюс более плотная упаковка данных.
Автоматизируется это следующим образом:
int main()
{
    poly_sequence<int, double> seq;

    for(int i=0; i!=3; ++i)
    {
        push_back(seq, i);
        push_back(seq, i+0.1);
    }

    for_each(seq, [](const auto &x)
    {
        cout << x << endl;
    });
}
// OUTPUT:
0
1
2
0.1
1.1
2.1
Re[3]: Variant по mpl types sequences как член класса - как сделать?
От: LowCoder  
Дата: 03.02.14 18:17
Оценка:

EP>    for_each(seq, [](const auto &x)
EP>    {


Симпатично.. но я к сожалению ограничен предыдущим стандартом.
Re[4]: Variant по mpl types sequences как член класса - как сделать?
От: Evgeny.Panasyuk Россия  
Дата: 03.02.14 18:39
Оценка:
Здравствуйте, LowCoder, Вы писали:

LC>Симпатично.. но я к сожалению ограничен предыдущим стандартом.


Это механически переписывается на C++98. Полиморфная лямбда просто заменяется классом с шаблонным operator(), а variadic template parameters на mpl sequence.
Причём изначально я делал пример именно для C++98
Автор: Evgeny.Panasyuk
Дата: 18.03.13
.
Re[5]: Variant по mpl types sequences как член класса - как сделать?
От: LowCoder  
Дата: 03.02.14 18:45
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, LowCoder, Вы писали:


LC>>Симпатично.. но я к сожалению ограничен предыдущим стандартом.


EP>Это механически переписывается на C++98. Полиморфная лямбда просто заменяется классом с шаблонным operator(), а variadic template parameters на mpl sequence.

EP>Причём изначально я делал пример именно для C++98
Автор: Evgeny.Panasyuk
Дата: 18.03.13
.



Да интересно. Благодарю.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.