From 2d6385031eff7f1c2379030590f5bb2b2697be91 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 9 Apr 2019 19:22:04 +0300 Subject: [PATCH] Fix emplace for types with a deleted move constructor (in the not trivially destructible case) --- include/boost/variant2/variant.hpp | 88 +++++++++++++++++------------- test/variant_emplace_type.cpp | 10 ++++ 2 files changed, 59 insertions(+), 39 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index e6c24d2..50aa99d 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -651,7 +651,7 @@ template struct variant_base_impl template BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_true, mp11::mp_bool, A&&... a ) { - static_assert( std::is_nothrow_constructible::value, "Logic error: U must be nothrow constructible from A&&" ); + static_assert( std::is_nothrow_constructible::value, "Logic error: U must be nothrow constructible from A&&..." ); st1_.emplace( mp11::mp_size_t(), std::forward(a)... ); ix_ = J; @@ -836,51 +836,61 @@ template struct variant_base_impl return st1_.get( mp11::mp_size_t() ); } + template void emplace_impl( mp11::mp_int<0>, A&&... a ) + { + static_assert( std::is_nothrow_constructible::value, "Logic error: U must be nothrow constructible from A&&..." ); + + _destroy(); + + st1_.emplace( mp11::mp_size_t(), std::forward(a)... ); + ix_ = J; + } + + template void emplace_impl( mp11::mp_int<1>, A&&... a ) + { + static_assert( can_be_valueless::value, "Logic error: T... must have a fallback type" ); + + std::size_t const K = valueless_index::value; + + static_assert( K < sizeof...(T), "Logic error: T... must have a fallback index" ); + + _destroy(); + + try + { + st1_.emplace( mp11::mp_size_t(), std::forward(a)... ); + ix_ = J; + } + catch( ... ) + { + st1_.emplace( mp11::mp_size_t() ); + ix_ = K+1; + + throw; + } + } + + template void emplace_impl( mp11::mp_int<2>, A&&... a ) + { + static_assert( std::is_nothrow_move_constructible::value, "Logic error: U must be nothrow move constructible" ); + + U tmp( std::forward(a)... ); + + _destroy(); + + st1_.emplace( mp11::mp_size_t(), std::move(tmp) ); + ix_ = J; + } + template void emplace( A&&... a ) { size_t const J = I+1; using U = mp11::mp_at_c, I>; - if( std::is_nothrow_constructible::value ) - { - _destroy(); + int const D = std::is_nothrow_constructible::value? 0: ( can_be_valueless::value? 1: 2 ); - st1_.emplace( mp11::mp_size_t(), std::forward(a)... ); - ix_ = J; - } - else if( can_be_valueless::value ) - { - std::size_t const K = valueless_index::value; - - assert( K < sizeof...(T) ); - - _destroy(); - - try - { - st1_.emplace( mp11::mp_size_t(), std::forward(a)... ); - ix_ = J; - } - catch( ... ) - { - st1_.emplace( mp11::mp_size_t() ); - ix_ = K+1; - - throw; - } - } - else - { - assert( std::is_nothrow_move_constructible::value ); - - U tmp( std::forward(a)... ); - - _destroy(); - - st1_.emplace( mp11::mp_size_t(), std::move(tmp) ); - ix_ = J; - } + this->emplace_impl( mp11::mp_int(), std::forward(a)... ); } }; diff --git a/test/variant_emplace_type.cpp b/test/variant_emplace_type.cpp index d7d86ee..df8b364 100644 --- a/test/variant_emplace_type.cpp +++ b/test/variant_emplace_type.cpp @@ -61,6 +61,11 @@ struct Y1 { }; +struct Y2 +{ + ~Y2() {} +}; + struct Guard { explicit Guard(int) {} @@ -180,5 +185,10 @@ int main() v.emplace( 1 ); } + { + variant v; + v.emplace( 1 ); + } + return boost::report_errors(); }