diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 9c1fba9..01b49d5 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -1768,6 +1768,25 @@ namespace detail template using remove_cv_ref_t = typename std::remove_cv::type>::type; +template variant const & extract_variant_base_( variant const & ); + +#if BOOST_WORKAROUND( BOOST_MSVC, < 1930 ) + +template struct extract_vbase_impl +{ + using type = decltype( extract_variant_base_( std::declval() ) ); +}; + +template using extract_variant_base = remove_cv_ref_t< typename extract_vbase_impl::type >; + +#else + +template using extract_variant_base = remove_cv_ref_t< decltype( extract_variant_base_( std::declval() ) ) >; + +#endif + +template using variant_base_size = variant_size< extract_variant_base >; + template struct copy_cv_ref { using type = T; @@ -1807,7 +1826,7 @@ template struct Qret template using front_if_same = mp11::mp_if, mp11::mp_front>; -template using apply_cv_ref = mp11::mp_product, mp11::mp_list>; +template using apply_cv_ref = mp11::mp_product, mp11::mp_list>; template using Vret = front_if_same, apply_cv_ref...>>; @@ -1836,7 +1855,7 @@ template struct visit_L1 template constexpr auto visit( F&& f, V1&& v1 ) -> detail::Vret { - return mp11::mp_with_index>( v1.index(), detail::visit_L1{ std::forward(f), std::forward(v1) } ); + return mp11::mp_with_index>( v1.index(), detail::visit_L1{ std::forward(f), std::forward(v1) } ); } #if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) || BOOST_WORKAROUND( BOOST_MSVC, < 1920 ) @@ -1878,7 +1897,7 @@ template struct visit_L2 template constexpr auto visit( F&& f, V1&& v1, V2&& v2 ) -> detail::Vret { - return mp11::mp_with_index>( v1.index(), detail::visit_L2{ std::forward(f), std::forward(v1), std::forward(v2) } ); + return mp11::mp_with_index>( v1.index(), detail::visit_L2{ std::forward(f), std::forward(v1), std::forward(v2) } ); } namespace detail @@ -1903,7 +1922,7 @@ template struct visit_L3 template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3 ) -> detail::Vret { - return mp11::mp_with_index>( v1.index(), detail::visit_L3{ std::forward(f), std::forward(v1), std::forward(v2), std::forward(v3) } ); + return mp11::mp_with_index>( v1.index(), detail::visit_L3{ std::forward(f), std::forward(v1), std::forward(v2), std::forward(v3) } ); } namespace detail @@ -1929,14 +1948,14 @@ template struct visit_L4 template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V3&& v3, V4&& v4 ) -> detail::Vret { - return mp11::mp_with_index>( v1.index(), detail::visit_L4{ std::forward(f), std::forward(v1), std::forward(v2), std::forward(v3), std::forward(v4) } ); + return mp11::mp_with_index>( v1.index(), detail::visit_L4{ std::forward(f), std::forward(v1), std::forward(v2), std::forward(v3), std::forward(v4) } ); } #else template constexpr auto visit( F&& f, V1&& v1, V2&& v2, V&&... v ) -> detail::Vret { - return mp11::mp_with_index>( v1.index(), [&]( auto I ){ + return mp11::mp_with_index>( v1.index(), [&]( auto I ){ auto f2 = [&]( auto&&... a ){ return std::forward(f)( detail::unsafe_get( std::forward(v1) ), std::forward(a)... ); }; return visit( f2, std::forward(v2), std::forward(v)... ); diff --git a/test/Jamfile b/test/Jamfile index 93bbb67..8242786 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -110,3 +110,5 @@ run variant_hash.cpp ; run variant_trivial.cpp ; run variant_special.cpp ; + +run variant_visit_derived.cpp ; diff --git a/test/variant_visit_derived.cpp b/test/variant_visit_derived.cpp new file mode 100644 index 0000000..ed33241 --- /dev/null +++ b/test/variant_visit_derived.cpp @@ -0,0 +1,57 @@ + +// Copyright 2017, 2020 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#if defined(_MSC_VER) +# pragma warning( disable: 4244 ) // conversion from float to int, possible loss of data +#endif + +#include +#include +#include +#include +#include + +struct X: boost::variant2::variant +{ +#if BOOST_WORKAROUND( BOOST_MSVC, < 1930 ) + + template explicit X( T&& t ): variant( std::forward( t ) ) {}; + +#else + + using variant::variant; + +#endif +}; + +template struct Y: boost::variant2::variant +{ + using boost::variant2::variant::variant; +}; + +int main() +{ + { + X v1( 1 ); + X const v2( 3.14f ); + + BOOST_TEST_EQ( (visit( []( int x1, float x2 ){ return (int)(x1 * 1000) + (int)(x2 * 100); }, v1, v2 )), 1314 ); + + visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, v1, v2 ); + visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, std::move(v1), std::move(v2) ); + } + + { + Y v1( 1 ); + Y const v2( 3.14f ); + + BOOST_TEST_EQ( (visit( []( int x1, float x2 ){ return (int)(x1 * 1000) + (int)(x2 * 100); }, v1, v2 )), 1314 ); + + visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, v1, v2 ); + visit( []( int x1, float x2 ){ BOOST_TEST_EQ( x1, 1 ); BOOST_TEST_EQ( x2, 3.14f ); }, std::move(v1), std::move(v2) ); + } + + return boost::report_errors(); +}