diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index e36f376..239e43f 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -2213,27 +2213,27 @@ void swap( variant & v, variant & w ) namespace detail { -template struct visit_by_index_L +template using Vret2 = mp11::mp_eval_if_not< std::is_same, R, front_if_same, mp11::mp_transform...>, apply_cv_ref> >; + +template struct visit_by_index_L { V&& v; std::tuple tp; - template void operator()( I ) const + template constexpr detail::Vret2 operator()( I ) const { - std::get( std::move(tp) )( unsafe_get( std::forward(v) ) ); + return std::get( std::move(tp) )( unsafe_get( std::forward(v) ) ); } }; } // namespace detail -template void visit_by_index( V&& v, F&&... f ) +template constexpr auto visit_by_index( V&& v, F&&... f ) -> detail::Vret2 { - constexpr auto N = variant_size::value; + static_assert( variant_size::value == sizeof...(F), "Incorrect number of function objects" ); - static_assert( N == sizeof...(F), "Incorrect number of function objects" ); - - mp11::mp_with_index( v.index(), - detail::visit_by_index_L{ std::forward(v), std::tuple( std::forward(f)... ) } ); + return mp11::mp_with_index::value>( v.index(), + detail::visit_by_index_L{ std::forward(v), std::tuple( std::forward(f)... ) } ); } // hashing support diff --git a/test/variant_visit_by_index.cpp b/test/variant_visit_by_index.cpp index e1939b4..865e532 100644 --- a/test/variant_visit_by_index.cpp +++ b/test/variant_visit_by_index.cpp @@ -4,9 +4,32 @@ #include #include +#include +#include #include using namespace boost::variant2; +using boost::mp11::mp_int; + +struct X +{ +}; + +struct F1 +{ + int operator()( X& ) const { return 1; } + int operator()( X const& ) const { return 2; } + int operator()( X&& ) const { return 3; } + int operator()( X const&& ) const { return 4; } +}; + +struct F2 +{ + mp_int<1> operator()( X& ) const { return {}; } + mp_int<2> operator()( X const& ) const { return {}; } + mp_int<3> operator()( X&& ) const { return {}; } + mp_int<4> operator()( X const&& ) const { return {}; } +}; int main() { @@ -20,7 +43,7 @@ int main() } { - variant v( 1 ); + variant v( in_place_index_t<0>(), 1 ); visit_by_index( v, []( int const& x ){ BOOST_TEST_EQ( x, 1 ); }, @@ -46,5 +69,58 @@ int main() []( float const& x ){ BOOST_TEST_EQ( x, 3.14f ); } ); } + { + variant const v( 7 ); + + auto r = visit_by_index( v, + []( int const& x ) -> double { return x; }, + []( float const& x ) -> double { return x; } ); + + BOOST_TEST_TRAIT_SAME( decltype(r), double ); + BOOST_TEST_EQ( r, 7.0 ); + } + + { + variant const v( 2.0f ); + + auto r = visit_by_index( v, + []( int const& x ) { return x + 0.0; }, + []( float const& x ) { return x + 0.0; } ); + + BOOST_TEST_TRAIT_SAME( decltype(r), double ); + BOOST_TEST_EQ( r, 2.0 ); + } + + { + variant const v( 3.0 ); + + auto r = visit_by_index( v, + []( int const& x ) { return x; }, + []( float const& x ) { return x; }, + []( double const& x ) { return x; } ); + + BOOST_TEST_TRAIT_SAME( decltype(r), double ); + BOOST_TEST_EQ( r, 3.0 ); + } + + { + variant v; + variant const cv; + + F1 f1; + + BOOST_TEST_EQ( visit_by_index( v, f1 ), 1 ); + BOOST_TEST_EQ( visit_by_index( cv, f1 ), 2 ); + BOOST_TEST_EQ( visit_by_index( std::move( v ), f1 ), 3 ); + BOOST_TEST_EQ( visit_by_index( std::move( cv ), f1 ), 4 ); + + F2 f2; + + BOOST_TEST_EQ( visit_by_index( v, f2 ), 1 ); + BOOST_TEST_EQ( visit_by_index( cv, f2 ), 2 ); + BOOST_TEST_EQ( visit_by_index( std::move( v ), f2 ), 3 ); + BOOST_TEST_EQ( visit_by_index( std::move( cv ), f2 ), 4 ); + } + return boost::report_errors(); }