diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 4934a50..26b5dac 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -1,12 +1,9 @@ #ifndef BOOST_VARIANT2_VARIANT_HPP_INCLUDED #define BOOST_VARIANT2_VARIANT_HPP_INCLUDED -// Copyright 2017-2019 Peter Dimov. -// +// Copyright 2017-2026 Peter Dimov. // Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt +// https://www.boost.org/LICENSE_1_0.txt #if defined(_MSC_VER) && _MSC_VER < 1910 # pragma warning( push ) @@ -451,61 +448,106 @@ template constexpr variant_alternative_t struct get_if_impl_L1 +{ + V& v_; + + template constexpr U* fn( I, mp11::mp_true ) const noexcept + { + return &v_._get_impl( I() ); + } + + template constexpr U* fn( I, mp11::mp_false ) const noexcept + { + return nullptr; + } + + template constexpr U* operator()( I ) const noexcept + { + return this->fn( I(), std::is_same>() ); + } +}; + +template constexpr U* get_if_impl( variant& v ) noexcept +{ + return mp11::mp_with_index( v.index(), get_if_impl_L1< U, variant >{ v } ); +} + +template struct get_if_impl_L2 +{ + V const& v_; + + template constexpr U const* fn( I, mp11::mp_true ) const noexcept + { + return &v_._get_impl( I() ); + } + + template constexpr U const* fn( I, mp11::mp_false ) const noexcept + { + return nullptr; + } + + template constexpr U const* operator()( I ) const noexcept + { + return this->fn( I(), std::is_same>() ); + } +}; + +template constexpr U const* get_if_impl( variant const& v ) noexcept +{ + return mp11::mp_with_index( v.index(), get_if_impl_L2< U, variant >{ v } ); +} + +} // namespace detail + template constexpr U& get(variant& v) { - static_assert( mp11::mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); - - using I = mp11::mp_find, U>; - - return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), v._get_impl( I() ); + static_assert( mp11::mp_contains, U>::value, "The type must be present in the list of variant alternatives" ); + return ( !holds_alternative( v )? detail::throw_bad_variant_access(): (void)0 ), *detail::get_if_impl( v ); } template constexpr U&& get(variant&& v) { - static_assert( mp11::mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); - - using I = mp11::mp_find, U>; + static_assert( mp11::mp_contains, U>::value, "The type must be present in the list of variant alternatives" ); #if !BOOST_WORKAROUND(BOOST_MSVC, < 1930) - return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), std::move( v._get_impl( I() ) ); + return ( !holds_alternative( v )? detail::throw_bad_variant_access(): (void)0 ), std::move( *detail::get_if_impl( v ) ); #else - if( v.index() != I::value ) detail::throw_bad_variant_access(); - return std::move( v._get_impl( I() ) ); + if( !holds_alternative( v ) ) detail::throw_bad_variant_access(); + return std::move( *detail::get_if_impl( v ) ); #endif } template constexpr U const& get(variant const& v) { - static_assert( mp11::mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); - - using I = mp11::mp_find, U>; - - return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), v._get_impl( I() ); + static_assert( mp11::mp_contains, U>::value, "The type must be present in the list of variant alternatives" ); + return ( !holds_alternative( v )? detail::throw_bad_variant_access(): (void)0 ), *detail::get_if_impl( v ); } template constexpr U const&& get(variant const&& v) { - static_assert( mp11::mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); - - using I = mp11::mp_find, U>; + static_assert( mp11::mp_contains, U>::value, "The type must be present in the list of variant alternatives" ); #if !BOOST_WORKAROUND(BOOST_MSVC, < 1930) - return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), std::move( v._get_impl( I() ) ); + return ( !holds_alternative( v )? detail::throw_bad_variant_access(): (void)0 ), std::move( *detail::get_if_impl( v ) ); #else - if( v.index() != I::value ) detail::throw_bad_variant_access(); - return std::move( v._get_impl( I() ) ); + if( !holds_alternative( v ) ) detail::throw_bad_variant_access(); + return std::move( *detail::get_if_impl( v ) ); #endif } -// get_if +// get_if (index) template constexpr typename std::add_pointer>>::type get_if(variant* v) noexcept { @@ -519,22 +561,18 @@ template constexpr typename std::add_pointerindex() == I? &v->_get_impl( mp11::mp_size_t() ): 0; } +// get_if (type) + template constexpr typename std::add_pointer::type get_if(variant* v) noexcept { - static_assert( mp11::mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); - - using I = mp11::mp_find, U>; - - return v && v->index() == I::value? &v->_get_impl( I() ): 0; + static_assert( mp11::mp_contains, U>::value, "The type must be present in the list of variant alternatives" ); + return v && holds_alternative( *v )? detail::get_if_impl( *v ): 0; } -template constexpr typename std::add_pointer::type get_if(variant const * v) noexcept +template constexpr typename std::add_pointer::type get_if(variant const* v) noexcept { - static_assert( mp11::mp_count, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" ); - - using I = mp11::mp_find, U>; - - return v && v->index() == I::value? &v->_get_impl( I() ): 0; + static_assert( mp11::mp_contains, U>::value, "The type must be present in the list of variant alternatives" ); + return v && holds_alternative( *v )? detail::get_if_impl( *v ): 0; } // diff --git a/test/Jamfile b/test/Jamfile index 2ccfe79..4d88ebf 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -111,7 +111,12 @@ run variant_special.cpp ; run variant_visit_derived.cpp ; -run variant_many_types.cpp ; +# These two tests require /bigobj under GCC/Windows and CMake/VS2022 (for some reason) + +run variant_many_types.cpp : : : + gcc,windows:release + gcc,cygwin:release + ; run variant_visit_r.cpp : : : gcc,windows:release diff --git a/test/variant_copy_assign_cx.cpp b/test/variant_copy_assign_cx.cpp index 3d9f3d5..d46bf57 100644 --- a/test/variant_copy_assign_cx.cpp +++ b/test/variant_copy_assign_cx.cpp @@ -43,26 +43,26 @@ enum E #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) -template constexpr T test( A const& a ) +template constexpr variant_alternative_t test( A const& a ) { V v; v = a; - return get(v); + return get(v); } int main() { { constexpr variant v( 1 ); - constexpr auto w = test, int>( v ); + constexpr auto w = test, 0>( v ); STATIC_ASSERT( w == 1 ); } { constexpr variant v( 1 ); - constexpr auto w = test, X>( v ); + constexpr auto w = test, 0>( v ); STATIC_ASSERT( w == 1 ); } @@ -71,7 +71,7 @@ int main() { constexpr variant v( 1 ); - constexpr auto w = test, Y>( v ); + constexpr auto w = test, 0>( v ); STATIC_ASSERT( w == 1 ); } @@ -79,31 +79,31 @@ int main() { constexpr variant v( 1 ); - constexpr auto w = test, int>( v ); + constexpr auto w = test, 0>( v ); STATIC_ASSERT( w == 1 ); } { constexpr variant v( 3.0f ); - constexpr auto w = test, float>( v ); + constexpr auto w = test, 1>( v ); STATIC_ASSERT( w == 3.0f ); } { constexpr variant v( 3.0f ); - constexpr auto w = test, float>( v ); + constexpr auto w = test, 2>( v ); STATIC_ASSERT( w == 3.0f ); } { constexpr variant v( 1 ); - constexpr auto w = test, X>( v ); + constexpr auto w = test, 2>( v ); STATIC_ASSERT( w == 1 ); } { constexpr variant v( X(1) ); - constexpr auto w = test, X>( v ); + constexpr auto w = test, 4>( v ); STATIC_ASSERT( w == 1 ); } @@ -112,13 +112,13 @@ int main() { constexpr variant v( 1 ); - constexpr auto w = test, Y>( v ); + constexpr auto w = test, 2>( v ); STATIC_ASSERT( w == 1 ); } { constexpr variant v( Y(1) ); - constexpr auto w = test, Y>( v ); + constexpr auto w = test, 4>( v ); STATIC_ASSERT( w == 1 ); } diff --git a/test/variant_copy_construct_cx.cpp b/test/variant_copy_construct_cx.cpp index 3e31006..1e04886 100644 --- a/test/variant_copy_construct_cx.cpp +++ b/test/variant_copy_construct_cx.cpp @@ -38,22 +38,22 @@ enum E #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) -template constexpr T test( V const v ) +template constexpr variant_alternative_t test( V const v ) { - return get( v ); + return get( v ); } int main() { { constexpr variant v( 1 ); - constexpr auto w = test( v ); + constexpr auto w = test<0>( v ); STATIC_ASSERT( w == 1 ); } { constexpr variant v( 1 ); - constexpr auto w = test( v ); + constexpr auto w = test<0>( v ); STATIC_ASSERT( w == 1 ); } @@ -62,7 +62,7 @@ int main() { constexpr variant v( 1 ); - constexpr auto w = test( v ); + constexpr auto w = test<0>( v ); STATIC_ASSERT( w == 1 ); } @@ -70,31 +70,31 @@ int main() { constexpr variant v( 1 ); - constexpr auto w = test( v ); + constexpr auto w = test<0>( v ); STATIC_ASSERT( w == 1 ); } { constexpr variant v( 3.0f ); - constexpr auto w = test( v ); + constexpr auto w = test<1>( v ); STATIC_ASSERT( w == 3.0f ); } { constexpr variant v( 3.0f ); - constexpr auto w = test( v ); + constexpr auto w = test<2>( v ); STATIC_ASSERT( w == 3.0f ); } { constexpr variant v( 1 ); - constexpr auto w = test( v ); + constexpr auto w = test<2>( v ); STATIC_ASSERT( w == 1 ); } { constexpr variant v( X(1) ); - constexpr auto w = test( v ); + constexpr auto w = test<4>( v ); STATIC_ASSERT( w == 1 ); } @@ -103,13 +103,13 @@ int main() { constexpr variant v( 1 ); - constexpr auto w = test( v ); + constexpr auto w = test<2>( v ); STATIC_ASSERT( w == 1 ); } { constexpr variant v( Y(1) ); - constexpr auto w = test( v ); + constexpr auto w = test<4>( v ); STATIC_ASSERT( w == 1 ); } diff --git a/test/variant_emplace_type_cx.cpp b/test/variant_emplace_type_cx.cpp index fe801eb..88ec0e9 100644 --- a/test/variant_emplace_type_cx.cpp +++ b/test/variant_emplace_type_cx.cpp @@ -33,24 +33,24 @@ struct Y #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) -template constexpr A test( A const& a ) +template> constexpr T test( A const& a ) { V v; v.template emplace( a ); - return get(v); + return get(v); } int main() { { - constexpr auto w = test, int>( 1 ); + constexpr auto w = test, 0>( 1 ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test, X>( 1 ); + constexpr auto w = test, 0>( 1 ); STATIC_ASSERT( w == 1 ); } @@ -58,29 +58,29 @@ int main() #else { - constexpr auto w = test, Y>( 1 ); + constexpr auto w = test, 0>( 1 ); STATIC_ASSERT( w == 1 ); } #endif { - constexpr auto w = test, int>( 1 ); + constexpr auto w = test, 0>( 1 ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test, float>( 3.0f ); + constexpr auto w = test, 1>( 3.0f ); STATIC_ASSERT( w == 3.0f ); } { - constexpr auto w = test, float>( 3.0f ); + constexpr auto w = test, 2>( 3.0f ); STATIC_ASSERT( w == 3.0f ); } { - constexpr auto w = test, X>( 1 ); + constexpr auto w = test, 4>( 1 ); STATIC_ASSERT( w == 1 ); } @@ -88,7 +88,7 @@ int main() #else { - constexpr auto w = test, Y>( 1 ); + constexpr auto w = test, 4>( 1 ); STATIC_ASSERT( w == 1 ); } diff --git a/test/variant_get_by_type.cpp b/test/variant_get_by_type.cpp index 8f44a7e..722b60d 100644 --- a/test/variant_get_by_type.cpp +++ b/test/variant_get_by_type.cpp @@ -1,10 +1,6 @@ - -// Copyright 2017 Peter Dimov. -// +// Copyright 2017, 2026 Peter Dimov. // Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt +// https://www.boost.org/LICENSE_1_0.txt #if defined( __clang__ ) && defined( __has_warning ) # if __has_warning( "-Wdeprecated-volatile" ) @@ -217,6 +213,9 @@ int main() BOOST_TEST_EQ( get(v), 0 ); BOOST_TEST_EQ( get_if(&v), &get(v) ); + BOOST_TEST_THROWS( get(v), bad_variant_access ); + BOOST_TEST_EQ( get_if(&v), nullptr ); + BOOST_TEST_EQ( get(std::move(v)), 0 ); } @@ -226,6 +225,9 @@ int main() BOOST_TEST_EQ( get(v), 0 ); BOOST_TEST_EQ( get_if(&v), &get(v) ); + BOOST_TEST_THROWS( get(v), bad_variant_access ); + BOOST_TEST_EQ( get_if(&v), nullptr ); + BOOST_TEST_EQ( get(std::move(v)), 0 ); } @@ -235,6 +237,9 @@ int main() BOOST_TEST_EQ( get(v), 1 ); BOOST_TEST_EQ( get_if(&v), &get(v) ); + BOOST_TEST_THROWS( get(v), bad_variant_access ); + BOOST_TEST_EQ( get_if(&v), nullptr ); + BOOST_TEST_EQ( get(std::move(v)), 1 ); } @@ -244,12 +249,18 @@ int main() BOOST_TEST_EQ( get(v), 1 ); BOOST_TEST_EQ( get_if(&v), &get(v) ); + BOOST_TEST_THROWS( get(v), bad_variant_access ); + BOOST_TEST_EQ( get_if(&v), nullptr ); + BOOST_TEST_EQ( get(std::move(v)), 1 ); } { variant v( 3.14f ); + BOOST_TEST_THROWS( get(v), bad_variant_access ); + BOOST_TEST_EQ( get_if(&v), nullptr ); + BOOST_TEST_EQ( get(v), 3.14f ); BOOST_TEST_EQ( get_if(&v), &get(v) ); @@ -259,6 +270,9 @@ int main() { variant const v( 3.14f ); + BOOST_TEST_THROWS( get(v), bad_variant_access ); + BOOST_TEST_EQ( get_if(&v), nullptr ); + BOOST_TEST_EQ( get(v), 3.14f ); BOOST_TEST_EQ( get_if(&v), &get(v) ); @@ -301,11 +315,13 @@ int main() { variant * p = 0; + BOOST_TEST_EQ( get_if(p), nullptr ); BOOST_TEST_EQ( get_if(p), nullptr ); } { variant const * p = 0; + BOOST_TEST_EQ( get_if(p), nullptr ); BOOST_TEST_EQ( get_if(p), nullptr ); } diff --git a/test/variant_get_by_type_cx.cpp b/test/variant_get_by_type_cx.cpp index 376e137..e195846 100644 --- a/test/variant_get_by_type_cx.cpp +++ b/test/variant_get_by_type_cx.cpp @@ -3,12 +3,13 @@ // https://www.boost.org/LICENSE_1_0.txt #include +#include #include #include -#if defined(BOOST_MSVC) && BOOST_MSVC < 1910 +#if !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR) -BOOST_PRAGMA_MESSAGE( "Test skipped because BOOST_MSVC < 1910" ) +BOOST_PRAGMA_MESSAGE("Test skipped because BOOST_MP11_HAS_CXX14_CONSTEXPR is not defined") int main() {} #else @@ -74,6 +75,7 @@ int main() STATIC_ASSERT( get(v) == 0 ); STATIC_ASSERT_IF( get_if(&v) == &get(v) ); + STATIC_ASSERT_IF( get_if(&v) == nullptr ); } { @@ -82,6 +84,7 @@ int main() STATIC_ASSERT( get(v) == 1 ); STATIC_ASSERT_IF( get_if(&v) == &get(v) ); + STATIC_ASSERT_IF( get_if(&v) == nullptr ); } { @@ -89,6 +92,7 @@ int main() STATIC_ASSERT( get(v) == (float)3.14f ); + STATIC_ASSERT_IF( get_if(&v) == nullptr ); STATIC_ASSERT_IF( get_if(&v) == &get(v) ); } } diff --git a/test/variant_move_assign_cx.cpp b/test/variant_move_assign_cx.cpp index 1f12f18..b41cece 100644 --- a/test/variant_move_assign_cx.cpp +++ b/test/variant_move_assign_cx.cpp @@ -44,24 +44,24 @@ enum E #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) -template constexpr T test( A&& a ) +template constexpr variant_alternative_t test( A&& a ) { V v; v = std::forward(a); - return get(v); + return get(v); } int main() { { - constexpr auto w = test, int>( variant( 1 ) ); + constexpr auto w = test, 0>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test, X>( variant( 1 ) ); + constexpr auto w = test, 0>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } @@ -69,34 +69,34 @@ int main() #else { - constexpr auto w = test, Y>( variant( 1 ) ); + constexpr auto w = test, 0>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } #endif { - constexpr auto w = test, int>( variant( 1 ) ); + constexpr auto w = test, 0>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test, float>( variant( 3.0f ) ); + constexpr auto w = test, 1>( variant( 3.0f ) ); STATIC_ASSERT( w == 3.0f ); } { - constexpr auto w = test, float>( variant( 3.0f ) ); + constexpr auto w = test, 2>( variant( 3.0f ) ); STATIC_ASSERT( w == 3.0f ); } { - constexpr auto w = test, X>( variant( 1 ) ); + constexpr auto w = test, 2>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test, X>( variant( X(1) ) ); + constexpr auto w = test, 4>( variant( X(1) ) ); STATIC_ASSERT( w == 1 ); } @@ -104,12 +104,12 @@ int main() #else { - constexpr auto w = test, Y>( variant( 1 ) ); + constexpr auto w = test, 2>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test, Y>( variant( Y(1) ) ); + constexpr auto w = test, 4>( variant( Y(1) ) ); STATIC_ASSERT( w == 1 ); } diff --git a/test/variant_move_construct_cx.cpp b/test/variant_move_construct_cx.cpp index 3ad69a9..84d6b74 100644 --- a/test/variant_move_construct_cx.cpp +++ b/test/variant_move_construct_cx.cpp @@ -39,21 +39,21 @@ enum E #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) -template constexpr T test( V&& v ) +template constexpr variant_alternative_t test( V&& v ) { V v2( std::forward(v) ); - return get( v2 ); + return get( v2 ); } int main() { { - constexpr auto w = test( variant( 1 ) ); + constexpr auto w = test<0>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test( variant( 1 ) ); + constexpr auto w = test<0>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } @@ -61,34 +61,34 @@ int main() #else { - constexpr auto w = test( variant( 1 ) ); + constexpr auto w = test<0>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } #endif { - constexpr auto w = test( variant( 1 ) ); + constexpr auto w = test<0>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test( variant( 3.0f ) ); + constexpr auto w = test<1>( variant( 3.0f ) ); STATIC_ASSERT( w == 3.0f ); } { - constexpr auto w = test( variant( 3.0f ) ); + constexpr auto w = test<2>( variant( 3.0f ) ); STATIC_ASSERT( w == 3.0f ); } { - constexpr auto w = test( variant( 1 ) ); + constexpr auto w = test<2>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test( variant( X(1) ) ); + constexpr auto w = test<4>( variant( X(1) ) ); STATIC_ASSERT( w == 1 ); } @@ -96,12 +96,12 @@ int main() #else { - constexpr auto w = test( variant( 1 ) ); + constexpr auto w = test<2>( variant( 1 ) ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test( variant( Y(1) ) ); + constexpr auto w = test<4>( variant( Y(1) ) ); STATIC_ASSERT( w == 1 ); } diff --git a/test/variant_value_assign_cx.cpp b/test/variant_value_assign_cx.cpp index efddfcf..65dab0f 100644 --- a/test/variant_value_assign_cx.cpp +++ b/test/variant_value_assign_cx.cpp @@ -38,24 +38,24 @@ enum E #define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__) -template constexpr A test( A const& a ) +template constexpr variant_alternative_t test( A const& a ) { V v; v = a; - return get(v); + return get(v); } int main() { { - constexpr auto w = test, int>( 1 ); + constexpr auto w = test, 0>( 1 ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test, X>( 1 ); + constexpr auto w = test, 0>( 1 ); STATIC_ASSERT( w == 1 ); } @@ -63,34 +63,34 @@ int main() #else { - constexpr auto w = test, Y>( 1 ); + constexpr auto w = test, 0>( 1 ); STATIC_ASSERT( w == 1 ); } #endif { - constexpr auto w = test, int>( 1 ); + constexpr auto w = test, 0>( 1 ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test, float>( 3.0f ); + constexpr auto w = test, 1>( 3.0f ); STATIC_ASSERT( w == 3.0f ); } { - constexpr auto w = test, float>( 3.0f ); + constexpr auto w = test, 2>( 3.0f ); STATIC_ASSERT( w == 3.0f ); } { - constexpr auto w = test, X>( 1 ); + constexpr auto w = test, 2>( 1 ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test, X>( X(1) ); + constexpr auto w = test, 4>( X(1) ); STATIC_ASSERT( w == 1 ); } @@ -98,12 +98,12 @@ int main() #else { - constexpr auto w = test, Y>( 1 ); + constexpr auto w = test, 2>( 1 ); STATIC_ASSERT( w == 1 ); } { - constexpr auto w = test, Y>( Y(1) ); + constexpr auto w = test, 4>( Y(1) ); STATIC_ASSERT( w == 1 ); }