From 3b2fb1a48a41751a381c899c76570d2ee79b148a Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 22 Jan 2020 19:59:59 +0200 Subject: [PATCH] Split variant_copy_base into separate cc/ca/mc/ma bases; avoids multiple inheritance, which is a penalty in the MS ABI --- include/boost/variant2/variant.hpp | 354 +++++++++++++++++++++++++---- 1 file changed, 304 insertions(+), 50 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 0b0d9c9..8c1c308 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -1052,12 +1052,9 @@ template struct is_nothrow_swappable: mp11::mp_valid struct variant_copy_base_impl; @@ -1093,10 +1090,10 @@ private: public: - // constructors - variant_copy_base_impl() = default; + // copy constructor + template...>, E1> > @@ -1130,40 +1127,11 @@ public: mp11::mp_with_index( r.index(), L1{ this, r } ); } - template...>, E1> - > - constexpr variant_copy_base_impl( variant_copy_base_impl && r ) noexcept - : variant_base( static_cast(r) ) - { - } + // move constructor - // assignment + variant_copy_base_impl( variant_copy_base_impl && ) = default; -private: - - struct L2 - { - variant_base * this_; - variant_copy_base_impl & r; - - template void operator()( I i ) const - { - this_->_replace( i, std::move( r._get_impl( i ) ) ); - } - }; - -public: - - template...>>, E1>, - class E3 = mp11::mp_if...>, E1> - > - variant_copy_base_impl( variant_copy_base_impl && r ) - noexcept( mp11::mp_all...>::value ) - { - mp11::mp_with_index( r.index(), L2{ this, r } ); - } + // copy assignment template..., detail::is_trivially_copy_constructible..., detail::is_trivially_copy_assignable...>, E1> @@ -1200,6 +1168,8 @@ public: return *this; } + // move assignment + template..., detail::is_trivially_move_constructible..., detail::is_trivially_move_assignable...>, E1> > @@ -1236,34 +1206,318 @@ public: } }; -} // namespace detail +*/ -// disable_move_constructor +// variant_cc_base -namespace detail +template struct variant_cc_base_impl; + +template using variant_cc_base = variant_cc_base_impl< + mp11::mp_all...>::value, + mp11::mp_all...>::value, + T...>; + +template struct variant_cc_base_impl: public variant_base { + using variant_base = detail::variant_base; + using variant_base::variant_base; -template struct disable_move_constructor; - -template<> struct disable_move_constructor -{ + variant_cc_base_impl() = default; + variant_cc_base_impl( variant_cc_base_impl const& ) = default; + variant_cc_base_impl( variant_cc_base_impl && ) = default; + variant_cc_base_impl& operator=( variant_cc_base_impl const& ) = default; + variant_cc_base_impl& operator=( variant_cc_base_impl && ) = default; }; -template<> struct disable_move_constructor +template struct variant_cc_base_impl: public variant_base { - disable_move_constructor() = default; - disable_move_constructor( disable_move_constructor && ) = delete; + using variant_base = detail::variant_base; + using variant_base::variant_base; + + variant_cc_base_impl() = default; + variant_cc_base_impl( variant_cc_base_impl const& ) = delete; + variant_cc_base_impl( variant_cc_base_impl && ) = default; + variant_cc_base_impl& operator=( variant_cc_base_impl const& ) = default; + variant_cc_base_impl& operator=( variant_cc_base_impl && ) = default; +}; + +template struct variant_cc_base_impl: public variant_base +{ + using variant_base = detail::variant_base; + using variant_base::variant_base; + +public: + + // constructors + + variant_cc_base_impl() = default; + + // copy constructor + +private: + + struct L1 + { + variant_base * this_; + variant_base const & r; + + template void operator()( I i ) const + { + this_->_replace( i, r._get_impl( i ) ); + } + }; + +public: + + variant_cc_base_impl( variant_cc_base_impl const& r ) + noexcept( mp11::mp_all...>::value ) + { + mp11::mp_with_index( r.index(), L1{ this, r } ); + } + + // move constructor + + variant_cc_base_impl( variant_cc_base_impl && ) = default; + + // assignment + + variant_cc_base_impl& operator=( variant_cc_base_impl const & ) = default; + variant_cc_base_impl& operator=( variant_cc_base_impl && ) = default; +}; + +// variant_ca_base + +template struct variant_ca_base_impl; + +template using variant_ca_base = variant_ca_base_impl< + mp11::mp_all..., std::is_copy_assignable...>::value, + mp11::mp_all..., detail::is_trivially_copy_constructible..., detail::is_trivially_copy_assignable...>::value, + T...>; + +template struct variant_ca_base_impl: public variant_cc_base +{ + using variant_base = detail::variant_cc_base; + using variant_base::variant_base; + + variant_ca_base_impl() = default; + variant_ca_base_impl( variant_ca_base_impl const& ) = default; + variant_ca_base_impl( variant_ca_base_impl && ) = default; + variant_ca_base_impl& operator=( variant_ca_base_impl const& ) = default; + variant_ca_base_impl& operator=( variant_ca_base_impl && ) = default; +}; + +template struct variant_ca_base_impl: public variant_cc_base +{ + using variant_base = detail::variant_cc_base; + using variant_base::variant_base; + + variant_ca_base_impl() = default; + variant_ca_base_impl( variant_ca_base_impl const& ) = default; + variant_ca_base_impl( variant_ca_base_impl && ) = default; + variant_ca_base_impl& operator=( variant_ca_base_impl const& ) = delete; + variant_ca_base_impl& operator=( variant_ca_base_impl && ) = default; +}; + +template struct variant_ca_base_impl: public variant_cc_base +{ + using variant_base = detail::variant_cc_base; + using variant_base::variant_base; + +public: + + // constructors + + variant_ca_base_impl() = default; + variant_ca_base_impl( variant_ca_base_impl const& ) = default; + variant_ca_base_impl( variant_ca_base_impl && ) = default; + + // copy assignment + +private: + + struct L3 + { + variant_base * this_; + variant_base const & r; + + template void operator()( I i ) const + { + this_->template emplace( r._get_impl( i ) ); + } + }; + +public: + + BOOST_CXX14_CONSTEXPR variant_ca_base_impl& operator=( variant_ca_base_impl const & r ) + noexcept( mp11::mp_all...>::value ) + { + mp11::mp_with_index( r.index(), L3{ this, r } ); + return *this; + } + + // move assignment + + variant_ca_base_impl& operator=( variant_ca_base_impl && ) = default; +}; + +// variant_mc_base + +template struct variant_mc_base_impl; + +template using variant_mc_base = variant_mc_base_impl< + mp11::mp_all...>::value, + mp11::mp_all...>::value, + T...>; + +template struct variant_mc_base_impl: public variant_ca_base +{ + using variant_base = detail::variant_ca_base; + using variant_base::variant_base; + + variant_mc_base_impl() = default; + variant_mc_base_impl( variant_mc_base_impl const& ) = default; + variant_mc_base_impl( variant_mc_base_impl && ) = default; + variant_mc_base_impl& operator=( variant_mc_base_impl const& ) = default; + variant_mc_base_impl& operator=( variant_mc_base_impl && ) = default; +}; + +template struct variant_mc_base_impl: public variant_ca_base +{ + using variant_base = detail::variant_ca_base; + using variant_base::variant_base; + + variant_mc_base_impl() = default; + variant_mc_base_impl( variant_mc_base_impl const& ) = default; + variant_mc_base_impl( variant_mc_base_impl && ) = delete; + variant_mc_base_impl& operator=( variant_mc_base_impl const& ) = default; + variant_mc_base_impl& operator=( variant_mc_base_impl && ) = default; +}; + +template struct variant_mc_base_impl: public variant_ca_base +{ + using variant_base = detail::variant_ca_base; + using variant_base::variant_base; + +public: + + // constructors + + variant_mc_base_impl() = default; + variant_mc_base_impl( variant_mc_base_impl const& ) = default; + + // move constructor + +private: + + struct L2 + { + variant_base * this_; + variant_base & r; + + template void operator()( I i ) const + { + this_->_replace( i, std::move( r._get_impl( i ) ) ); + } + }; + +public: + + variant_mc_base_impl( variant_mc_base_impl && r ) + noexcept( mp11::mp_all...>::value ) + { + mp11::mp_with_index( r.index(), L2{ this, r } ); + } + + // assignment + + variant_mc_base_impl& operator=( variant_mc_base_impl const & ) = default; + variant_mc_base_impl& operator=( variant_mc_base_impl && ) = default; +}; + +// variant_ma_base + +template struct variant_ma_base_impl; + +template using variant_ma_base = variant_ma_base_impl< + mp11::mp_all..., std::is_move_assignable...>::value, + mp11::mp_all..., detail::is_trivially_move_constructible..., detail::is_trivially_move_assignable...>::value, + T...>; + +template struct variant_ma_base_impl: public variant_mc_base +{ + using variant_base = detail::variant_mc_base; + using variant_base::variant_base; + + variant_ma_base_impl() = default; + variant_ma_base_impl( variant_ma_base_impl const& ) = default; + variant_ma_base_impl( variant_ma_base_impl && ) = default; + variant_ma_base_impl& operator=( variant_ma_base_impl const& ) = default; + variant_ma_base_impl& operator=( variant_ma_base_impl && ) = default; +}; + +template struct variant_ma_base_impl: public variant_mc_base +{ + using variant_base = detail::variant_mc_base; + using variant_base::variant_base; + + variant_ma_base_impl() = default; + variant_ma_base_impl( variant_ma_base_impl const& ) = default; + variant_ma_base_impl( variant_ma_base_impl && ) = default; + variant_ma_base_impl& operator=( variant_ma_base_impl const& ) = default; + variant_ma_base_impl& operator=( variant_ma_base_impl && ) = delete; +}; + +template struct variant_ma_base_impl: public variant_mc_base +{ + using variant_base = detail::variant_mc_base; + using variant_base::variant_base; + +public: + + // constructors + + variant_ma_base_impl() = default; + variant_ma_base_impl( variant_ma_base_impl const& ) = default; + variant_ma_base_impl( variant_ma_base_impl && ) = default; + + // copy assignment + + variant_ma_base_impl& operator=( variant_ma_base_impl const & ) = default; + + // move assignment + +private: + + struct L4 + { + variant_base * this_; + variant_base & r; + + template void operator()( I i ) const + { + this_->template emplace( std::move( r._get_impl( i ) ) ); + } + }; + +public: + + variant_ma_base_impl& operator=( variant_ma_base_impl && r ) + noexcept( mp11::mp_all...>::value ) + { + mp11::mp_with_index( r.index(), L4{ this, r } ); + return *this; + } }; } // namespace detail // variant -template class variant: private detail::variant_copy_base, private detail::disable_move_constructor...>::value> +template class variant: private detail::variant_ma_base { private: - using variant_base = detail::variant_copy_base; + using variant_base = detail::variant_ma_base; public: