четверг, 13 августа 2015 г.

[prog.c++] Еще живой пример влияния эволюции C++ на размер кода

Уже неоднократно говорил, что C++11 -- это совсем другой язык, нежели C++98/03. Если же появляется возможность использовать C++14, то это еще более другой язык. Под катом свежий пример.

Итак, нужно создать несколько новых объектов, одного типа, но получающих разные наборы параметров. Какие-то параметры в этих наборах одинаковые для всех объектов, какие-то различаются. В C++03 пришлось бы писать что-то вроде (если не прибегать к макросовой магии):

void create_machine_controllers(
   so_5::rt::agent_coop_t & coop,
   const so_5::rt::mbox_t & status_distrib_mbox,
   const machine_dictionary_t & machines )
{
   so_5::disp::prio::common_thread::private_dispatcher_handle_t disp =
         so_5::disp::prio::common_thread::create_private_disp(
               coop.environment() );

   coop.make_agent_with_binder< a_machine_controller_t >(
         disp->binder(),
         so_5::prio::p4,
         status_distrib_mbox,
         machines,
         engine_stopper_filter, engine_stopper_action );
   coop.make_agent_with_binder< a_machine_controller_t >(
         disp->binder(),
         so_5::prio::p3,
         status_distrib_mbox,
         machines,
         cooler_starter_filter, cooler_starter_action );
   coop.make_agent_with_binder< a_machine_controller_t >(
         disp->binder(),
         so_5::prio::p2,
         status_distrib_mbox,
         machines,
         engine_starter_filter, engine_starter_action );
   coop.make_agent_with_binder< a_machine_controller_t >(
         disp->binder(),
         so_5::prio::p1,
         status_distrib_mbox,
         machines,
         cooler_stopper_filter, cooler_stopper_action );
}

Писать такой код грустно и скучно. Поэтому, если бы пришлось ограничиваться только рамками С++03, то невольно руки потянулись бы к макросам. Однако, если есть возможность использовать С++11, то дело пойдет веселее:

void create_machine_controllers(
   so_5::rt::agent_coop_t & coop,
   const so_5::rt::mbox_t & status_distrib_mbox,
   const machine_dictionary_t & machines )
{
   auto disp = so_5::disp::prio::common_thread::create_private_disp(
         coop.environment() );

   auto maker = [&]( so_5::priority_t priority,
         a_machine_controller_t::filter_t filter,
         a_machine_controller_t::actor_t actor )
      {
         coop.make_agent_with_binder< a_machine_controller_t >(
               disp->binder(),
               priority,
               status_distrib_mbox,
               machines,
               std::move( filter ),
               std::move( actor ) );
      };

   maker( so_5::prio::p4, engine_stopper_filter, engine_stopper_action );
   maker( so_5::prio::p3, cooler_starter_filter, cooler_starter_action );
   maker( so_5::prio::p2, engine_starter_filter, engine_starter_action );
   maker( so_5::prio::p1, cooler_stopper_filter, cooler_stopper_action );
}

Ну а в C++14 будет и вовсе не скучно:

void create_machine_controllers(
   so_5::rt::agent_coop_t & coop,
   const so_5::rt::mbox_t & status_distrib_mbox,
   const machine_dictionary_t & machines )
{
   auto disp = so_5::disp::prio::common_thread::create_private_disp(
         coop.environment() );

   auto maker = [&]( auto priority, auto filter, auto actor )
      {
         coop.make_agent_with_binder< a_machine_controller_t >(
               disp->binder(),
               priority,
               status_distrib_mbox,
               machines,
               filter,
               actor );
      };

   maker( so_5::prio::p4, engine_stopper_filter, engine_stopper_action );
   maker( so_5::prio::p3, cooler_starter_filter, cooler_starter_action );
   maker( so_5::prio::p2, engine_starter_filter, engine_starter_action );
   maker( so_5::prio::p1, cooler_stopper_filter, cooler_stopper_action );
}

В общем, на современном C++ нужно учиться программировать заново. А уж от спектра имеющихся вариантов решения одной и той же задачки голова может пойти кругом :)

Комментариев нет: