суббота, 20 апреля 2019 г.

[prog.c++] Тот случай, когда жалко, что C++ный if constexpr не дотягивает до D-шного static if :(

Хорошо, когда C++ со временем впитывает в себя хорошие штуки из других языков программирования. Вот тот же if constexpr из C++17 явно позаимствован из D. Жаль только, что static if в D может применяться в большем количестве контекстов, чем if constexpr в C++.

Был бы в C++17 if constexpr таким же мощным, как static if в D, я бы мог написать вот такой вот код сходу, не сильно задумываясь:

template<
   typename Msg,
   message_mutability_t Mutability,
   message_ownership_t Ownership >
class message_holder_impl_t final
   {
   public :
      using payload_type = typename message_payload_type< Msg >::payload_type;
      using envelope_type = typename message_payload_type< Msg >::envelope_type;

      message_holder_impl_t() noexcept = default;

      message_holder_impl_t(
         intrusive_ptr_t< envelope_type > mf ) noexcept
         : m_msg{ std::move(mf) }
         {}

if constexpr(message_ownership_t::unique == Ownership )
   {
      message_holder_impl_t( const message_holder_impl_t & ) = delete;

      message_holder_impl_t( message_holder_impl_t && ) noexcept = default;

      message_holder_impl_t &
      operator=( const message_holder_impl_t & ) = delete;

      message_holder_impl_t &
      operator=( message_holder_impl_t && ) noexcept = default;

   }

      friend void
      swap( message_holder_impl_t & a, message_holder_impl_t & b ) noexcept
         {
            using std::swap;
            swap( a.m_msg, b.m_msg );
         }

      //! Access to the message.
      const payload_type *
      get() const noexcept
         {
            return get_const_ptr( m_msg );
         }

      //! Access to the message.
      const payload_type &
      operator * () const noexcept { return *get(); }

      //! Access to the message via pointer.
      const payload_type *
      operator->() const noexcept { return get(); }

if constexpr(message_mutability_t::mutable_message == Mutability)
   {
      //! Access to the message.
      payload_type *
      get() noexcept
         {
            return get_non_const_ptr( m_msg );
         }

      payload_type &
      operator * () noexcept { return *get(); }

      payload_type *
      operator->() noexcept { return get(); }
   }

if constexpr(message_ownership_t::shared == Ownership)
   {
      //! Create a smart pointer for the message envelope.
      intrusive_ptr_t< envelope_type >
      make_reference() const noexcept
         {
            return m_msg;
         }
   }
else if constexpr(message_ownership_t::unique == Ownership)
   {
      //! Create a smart pointer for the message envelope.
      intrusive_ptr_t< envelope_type >
      make_reference() noexcept
         {
            return { std::move(m_msg) };
         }
   }

   private :
      //! Actual message.
      intrusive_ptr_t< envelope_type > m_msg;
   };

Т.е. состав шаблонного класса и логика поведения отдельных его методов могла бы определяться посредством простых if-ов. Должен message_holder реализовать идиому уникального хранения? Нет проблем, будут у него только конструктор и оператор перемещения, без конструктора/оператора копирования. Хранит message_holder мутабельное сообщение? Не вопрос, просто добавляем неконстантный доступ к содержимому message_holder-а.

Но, к сожалению, такого счастья нам еще не подвезли. Придется теперь ломать голову о том, как достичь этого же эффекта посредством наследования и миксинов...

3 комментария:

Сергей Скороходов комментирует...

А в D что, static if и за условную компиляцию отвечает?! Удобно. Впрочем, Уолтер всегда был ненормальным...;)

Igor Mironchik комментирует...

А я вот не согласная с таким static if, да - код писать удобно, но вот читаемость кода снижается на мой взгляд, без бутылки с такими классами не разберешься... В С++ код читать легко, все выверенно, все взвешенно, не зря бухают эти комитеты по стандартизации...

eao197 комментирует...

@Сергей Скороходов

Формально за условную компиляцию в D отвечает конструкция version. Но к ней в довесок идут static if и static foreach. И в результате получается инструмент страшной силы :)