Skip to content

Commit ca64e5a

Browse files
committed
Relax get<T> constraint to permit duplicate alternatives. Refs #33.
1 parent 3b731db commit ca64e5a

9 files changed

Lines changed: 174 additions & 116 deletions

include/boost/variant2/variant.hpp

Lines changed: 76 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
#ifndef BOOST_VARIANT2_VARIANT_HPP_INCLUDED
22
#define BOOST_VARIANT2_VARIANT_HPP_INCLUDED
33

4-
// Copyright 2017-2019 Peter Dimov.
5-
//
4+
// Copyright 2017-2026 Peter Dimov.
65
// Distributed under the Boost Software License, Version 1.0.
7-
//
8-
// See accompanying file LICENSE_1_0.txt or copy at
9-
// http://www.boost.org/LICENSE_1_0.txt
6+
// https://www.boost.org/LICENSE_1_0.txt
107

118
#if defined(_MSC_VER) && _MSC_VER < 1910
129
# pragma warning( push )
@@ -451,61 +448,106 @@ template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T
451448

452449
// get (type)
453450

454-
template<class U, class... T> constexpr U& get(variant<T...>& v)
451+
namespace detail
452+
{
453+
454+
template<class U, class V> struct get_if_impl_L1
455455
{
456-
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
456+
V& v_;
457457

458-
using I = mp11::mp_find<variant<T...>, U>;
458+
template<class I> constexpr U* fn( I, mp11::mp_true ) const noexcept
459+
{
460+
return &v_._get_impl( I() );
461+
}
462+
463+
template<class I> constexpr U* fn( I, mp11::mp_false ) const noexcept
464+
{
465+
return nullptr;
466+
}
459467

460-
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), v._get_impl( I() );
468+
template<class I> constexpr U* operator()( I ) const noexcept
469+
{
470+
return this->fn( I(), std::is_same<U, mp11::mp_at<V, I>>() );
471+
}
472+
};
473+
474+
template<class U, class... T> constexpr U* get_if_impl( variant<T...>& v ) noexcept
475+
{
476+
return mp11::mp_with_index<sizeof...(T)>( v.index(), get_if_impl_L1< U, variant<T...> >{ v } );
461477
}
462478

463-
template<class U, class... T> constexpr U&& get(variant<T...>&& v)
479+
template<class U, class V> struct get_if_impl_L2
480+
{
481+
V const& v_;
482+
483+
template<class I> constexpr U const* fn( I, mp11::mp_true ) const noexcept
484+
{
485+
return &v_._get_impl( I() );
486+
}
487+
488+
template<class I> constexpr U const* fn( I, mp11::mp_false ) const noexcept
489+
{
490+
return nullptr;
491+
}
492+
493+
template<class I> constexpr U const* operator()( I ) const noexcept
494+
{
495+
return this->fn( I(), std::is_same<U, mp11::mp_at<V, I>>() );
496+
}
497+
};
498+
499+
template<class U, class... T> constexpr U const* get_if_impl( variant<T...> const& v ) noexcept
464500
{
465-
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
501+
return mp11::mp_with_index<sizeof...(T)>( v.index(), get_if_impl_L2< U, variant<T...> >{ v } );
502+
}
503+
504+
} // namespace detail
466505

467-
using I = mp11::mp_find<variant<T...>, U>;
506+
template<class U, class... T> constexpr U& get(variant<T...>& v)
507+
{
508+
static_assert( mp11::mp_contains<variant<T...>, U>::value == 1, "The type must be present in the list of variant alternatives" );
509+
return ( !holds_alternative<U>( v )? detail::throw_bad_variant_access(): (void)0 ), *detail::get_if_impl<U>( v );
510+
}
511+
512+
template<class U, class... T> constexpr U&& get(variant<T...>&& v)
513+
{
514+
static_assert( mp11::mp_contains<variant<T...>, U>::value == 1, "The type must be present in the list of variant alternatives" );
468515

469516
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
470517

471-
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), std::move( v._get_impl( I() ) );
518+
return ( !holds_alternative<U>( v )? detail::throw_bad_variant_access(): (void)0 ), std::move( *detail::get_if_impl<U>( v ) );
472519

473520
#else
474521

475-
if( v.index() != I::value ) detail::throw_bad_variant_access();
476-
return std::move( v._get_impl( I() ) );
522+
if( !holds_alternative<U>( v ) ) detail::throw_bad_variant_access();
523+
return std::move( *detail::get_if_impl<U>( v ) );
477524

478525
#endif
479526
}
480527

481528
template<class U, class... T> constexpr U const& get(variant<T...> const& v)
482529
{
483-
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
484-
485-
using I = mp11::mp_find<variant<T...>, U>;
486-
487-
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), v._get_impl( I() );
530+
static_assert( mp11::mp_contains<variant<T...>, U>::value == 1, "The type must be present in the list of variant alternatives" );
531+
return ( !holds_alternative<U>( v )? detail::throw_bad_variant_access(): (void)0 ), *detail::get_if_impl<U>( v );
488532
}
489533

490534
template<class U, class... T> constexpr U const&& get(variant<T...> const&& v)
491535
{
492-
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
493-
494-
using I = mp11::mp_find<variant<T...>, U>;
536+
static_assert( mp11::mp_contains<variant<T...>, U>::value == 1, "The type must be present in the list of variant alternatives" );
495537

496538
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
497539

498-
return ( v.index() != I::value? detail::throw_bad_variant_access(): (void)0 ), std::move( v._get_impl( I() ) );
540+
return ( !holds_alternative<U>( v )? detail::throw_bad_variant_access(): (void)0 ), std::move( *detail::get_if_impl<U>( v ) );
499541

500542
#else
501543

502-
if( v.index() != I::value ) detail::throw_bad_variant_access();
503-
return std::move( v._get_impl( I() ) );
544+
if( !holds_alternative<U>( v ) ) detail::throw_bad_variant_access();
545+
return std::move( *detail::get_if_impl<U>( v ) );
504546

505547
#endif
506548
}
507549

508-
// get_if
550+
// get_if (index)
509551

510552
template<std::size_t I, class... T> constexpr typename std::add_pointer<variant_alternative_t<I, variant<T...>>>::type get_if(variant<T...>* v) noexcept
511553
{
@@ -519,22 +561,18 @@ template<std::size_t I, class... T> constexpr typename std::add_pointer<const va
519561
return v && v->index() == I? &v->_get_impl( mp11::mp_size_t<I>() ): 0;
520562
}
521563

564+
// get_if (type)
565+
522566
template<class U, class... T> constexpr typename std::add_pointer<U>::type get_if(variant<T...>* v) noexcept
523567
{
524-
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
525-
526-
using I = mp11::mp_find<variant<T...>, U>;
527-
528-
return v && v->index() == I::value? &v->_get_impl( I() ): 0;
568+
static_assert( mp11::mp_contains<variant<T...>, U>::value == 1, "The type must be present in the list of variant alternatives" );
569+
return v && holds_alternative<U>( *v )? detail::get_if_impl<U>( *v ): 0;
529570
}
530571

531-
template<class U, class... T> constexpr typename std::add_pointer<U const>::type get_if(variant<T...> const * v) noexcept
572+
template<class U, class... T> constexpr typename std::add_pointer<U const>::type get_if(variant<T...> const* v) noexcept
532573
{
533-
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
534-
535-
using I = mp11::mp_find<variant<T...>, U>;
536-
537-
return v && v->index() == I::value? &v->_get_impl( I() ): 0;
574+
static_assert( mp11::mp_contains<variant<T...>, U>::value == 1, "The type must be present in the list of variant alternatives" );
575+
return v && holds_alternative<U>( *v )? detail::get_if_impl<U>( *v ): 0;
538576
}
539577

540578
//

test/variant_copy_assign_cx.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,26 @@ enum E
4343

4444
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
4545

46-
template<class V, class T, class A> constexpr T test( A const& a )
46+
template<class V, std::size_t I, class A> constexpr variant_alternative_t<I, V> test( A const& a )
4747
{
4848
V v;
4949

5050
v = a;
5151

52-
return get<T>(v);
52+
return get<I>(v);
5353
}
5454

5555
int main()
5656
{
5757
{
5858
constexpr variant<int> v( 1 );
59-
constexpr auto w = test<variant<int>, int>( v );
59+
constexpr auto w = test<variant<int>, 0>( v );
6060
STATIC_ASSERT( w == 1 );
6161
}
6262

6363
{
6464
constexpr variant<X> v( 1 );
65-
constexpr auto w = test<variant<X>, X>( v );
65+
constexpr auto w = test<variant<X>, 0>( v );
6666
STATIC_ASSERT( w == 1 );
6767
}
6868

@@ -71,39 +71,39 @@ int main()
7171

7272
{
7373
constexpr variant<Y> v( 1 );
74-
constexpr auto w = test<variant<Y>, Y>( v );
74+
constexpr auto w = test<variant<Y>, 0>( v );
7575
STATIC_ASSERT( w == 1 );
7676
}
7777

7878
#endif
7979

8080
{
8181
constexpr variant<int, float> v( 1 );
82-
constexpr auto w = test<variant<int, float>, int>( v );
82+
constexpr auto w = test<variant<int, float>, 0>( v );
8383
STATIC_ASSERT( w == 1 );
8484
}
8585

8686
{
8787
constexpr variant<int, float> v( 3.0f );
88-
constexpr auto w = test<variant<int, float>, float>( v );
88+
constexpr auto w = test<variant<int, float>, 1>( v );
8989
STATIC_ASSERT( w == 3.0f );
9090
}
9191

9292
{
9393
constexpr variant<int, int, float> v( 3.0f );
94-
constexpr auto w = test<variant<int, int, float>, float>( v );
94+
constexpr auto w = test<variant<int, int, float>, 2>( v );
9595
STATIC_ASSERT( w == 3.0f );
9696
}
9797

9898
{
9999
constexpr variant<E, E, X> v( 1 );
100-
constexpr auto w = test<variant<E, E, X>, X>( v );
100+
constexpr auto w = test<variant<E, E, X>, 2>( v );
101101
STATIC_ASSERT( w == 1 );
102102
}
103103

104104
{
105105
constexpr variant<int, int, float, float, X> v( X(1) );
106-
constexpr auto w = test<variant<int, int, float, float, X>, X>( v );
106+
constexpr auto w = test<variant<int, int, float, float, X>, 4>( v );
107107
STATIC_ASSERT( w == 1 );
108108
}
109109

@@ -112,13 +112,13 @@ int main()
112112

113113
{
114114
constexpr variant<E, E, Y> v( 1 );
115-
constexpr auto w = test<variant<E, E, Y>, Y>( v );
115+
constexpr auto w = test<variant<E, E, Y>, 2>( v );
116116
STATIC_ASSERT( w == 1 );
117117
}
118118

119119
{
120120
constexpr variant<int, int, float, float, Y> v( Y(1) );
121-
constexpr auto w = test<variant<int, int, float, float, Y>, Y>( v );
121+
constexpr auto w = test<variant<int, int, float, float, Y>, 4>( v );
122122
STATIC_ASSERT( w == 1 );
123123
}
124124

test/variant_copy_construct_cx.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,22 @@ enum E
3838

3939
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
4040

41-
template<class T, class V> constexpr T test( V const v )
41+
template<std::size_t I, class V> constexpr variant_alternative_t<I, V> test( V const v )
4242
{
43-
return get<T>( v );
43+
return get<I>( v );
4444
}
4545

4646
int main()
4747
{
4848
{
4949
constexpr variant<int> v( 1 );
50-
constexpr auto w = test<int>( v );
50+
constexpr auto w = test<0>( v );
5151
STATIC_ASSERT( w == 1 );
5252
}
5353

5454
{
5555
constexpr variant<X> v( 1 );
56-
constexpr auto w = test<X>( v );
56+
constexpr auto w = test<0>( v );
5757
STATIC_ASSERT( w == 1 );
5858
}
5959

@@ -62,39 +62,39 @@ int main()
6262

6363
{
6464
constexpr variant<Y> v( 1 );
65-
constexpr auto w = test<Y>( v );
65+
constexpr auto w = test<0>( v );
6666
STATIC_ASSERT( w == 1 );
6767
}
6868

6969
#endif
7070

7171
{
7272
constexpr variant<int, float> v( 1 );
73-
constexpr auto w = test<int>( v );
73+
constexpr auto w = test<0>( v );
7474
STATIC_ASSERT( w == 1 );
7575
}
7676

7777
{
7878
constexpr variant<int, float> v( 3.0f );
79-
constexpr auto w = test<float>( v );
79+
constexpr auto w = test<1>( v );
8080
STATIC_ASSERT( w == 3.0f );
8181
}
8282

8383
{
8484
constexpr variant<int, int, float> v( 3.0f );
85-
constexpr auto w = test<float>( v );
85+
constexpr auto w = test<2>( v );
8686
STATIC_ASSERT( w == 3.0f );
8787
}
8888

8989
{
9090
constexpr variant<E, E, X> v( 1 );
91-
constexpr auto w = test<X>( v );
91+
constexpr auto w = test<2>( v );
9292
STATIC_ASSERT( w == 1 );
9393
}
9494

9595
{
9696
constexpr variant<int, int, float, float, X> v( X(1) );
97-
constexpr auto w = test<X>( v );
97+
constexpr auto w = test<4>( v );
9898
STATIC_ASSERT( w == 1 );
9999
}
100100

@@ -103,13 +103,13 @@ int main()
103103

104104
{
105105
constexpr variant<E, E, Y> v( 1 );
106-
constexpr auto w = test<Y>( v );
106+
constexpr auto w = test<2>( v );
107107
STATIC_ASSERT( w == 1 );
108108
}
109109

110110
{
111111
constexpr variant<int, int, float, float, Y> v( Y(1) );
112-
constexpr auto w = test<Y>( v );
112+
constexpr auto w = test<4>( v );
113113
STATIC_ASSERT( w == 1 );
114114
}
115115

0 commit comments

Comments
 (0)