Skip to content

Commit 3b731db

Browse files
committed
Relax holds_alternative constraint to permit duplicate alternatives. Refs #33.
1 parent 25a8596 commit 3b731db

3 files changed

Lines changed: 71 additions & 8 deletions

File tree

include/boost/variant2/variant.hpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,12 +324,41 @@ constexpr std::size_t variant_npos = ~static_cast<std::size_t>( 0 );
324324

325325
// holds_alternative
326326

327+
#if !defined(BOOST_MP11_HAS_CXX14_CONSTEXPR)
328+
327329
template<class U, class... T> constexpr bool holds_alternative( variant<T...> const& v ) noexcept
328330
{
329-
static_assert( mp11::mp_count<variant<T...>, U>::value == 1, "The type must occur exactly once in the list of variant alternatives" );
330-
return v.index() == mp11::mp_find<variant<T...>, U>::value;
331+
static_assert( mp11::mp_contains<variant<T...>, U>::value, "The type must be present in the list of variant alternatives" );
332+
333+
using A = bool[];
334+
return A{ std::is_same<U, T>::value... }[ v.index() ];
335+
}
336+
337+
#else
338+
339+
namespace detail
340+
{
341+
342+
template<class U, class V> struct holds_alternative_L
343+
{
344+
template<class I> constexpr bool operator()( I ) const noexcept
345+
{
346+
return std::is_same< U, mp11::mp_at<V, I> >::value;
347+
}
348+
};
349+
350+
} // namespace detail
351+
352+
template<class U, class... T> constexpr bool holds_alternative( variant<T...> const& v ) noexcept
353+
{
354+
using V = variant<T...>;
355+
static_assert( mp11::mp_contains<V, U>::value, "The type must be present in the list of variant alternatives" );
356+
357+
return mp11::mp_with_index<sizeof...(T)>( v.index(), detail::holds_alternative_L<U, V>() );
331358
}
332359

360+
#endif
361+
333362
// get (index)
334363

335364
template<std::size_t I, class... T> constexpr variant_alternative_t<I, variant<T...>>& get(variant<T...>& v)

test/variant_holds_alternative.cpp

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
2-
// Copyright 2017 Peter Dimov.
3-
//
1+
// Copyright 2017, 2026 Peter Dimov.
42
// Distributed under the Boost Software License, Version 1.0.
5-
//
6-
// See accompanying file LICENSE_1_0.txt or copy at
7-
// http://www.boost.org/LICENSE_1_0.txt
3+
// https://www.boost.org/LICENSE_1_0.txt
84

95
#include <boost/variant2/variant.hpp>
106
#include <boost/core/lightweight_test.hpp>
@@ -34,13 +30,27 @@ int main()
3430
{
3531
variant<int, float, float> v;
3632
BOOST_TEST( holds_alternative<int>( v ) );
33+
BOOST_TEST( !holds_alternative<float>( v ) );
3734
}
3835

3936
{
4037
variant<int, int, float> v( 3.14f );
38+
BOOST_TEST( !holds_alternative<int>( v ) );
4139
BOOST_TEST( holds_alternative<float>( v ) );
4240
}
4341

42+
{
43+
variant<int, int, float> v( in_place_index_t<0>{} );
44+
BOOST_TEST( holds_alternative<int>( v ) );
45+
BOOST_TEST( !holds_alternative<float>( v ) );
46+
}
47+
48+
{
49+
variant<int, int, float> v( in_place_index_t<1>{} );
50+
BOOST_TEST( holds_alternative<int>( v ) );
51+
BOOST_TEST( !holds_alternative<float>( v ) );
52+
}
53+
4454
{
4555
variant<int, float, std::string> v;
4656
BOOST_TEST( holds_alternative<int>( v ) );
@@ -64,15 +74,31 @@ int main()
6474

6575
{
6676
variant<int, int, float, std::string> v( 3.14f );
77+
BOOST_TEST( !holds_alternative<int>( v ) );
6778
BOOST_TEST( holds_alternative<float>( v ) );
6879
BOOST_TEST( !holds_alternative<std::string>( v ) );
6980
}
7081

7182
{
7283
variant<int, int, float, std::string> v( "text" );
84+
BOOST_TEST( !holds_alternative<int>( v ) );
7385
BOOST_TEST( !holds_alternative<float>( v ) );
7486
BOOST_TEST( holds_alternative<std::string>( v ) );
7587
}
7688

89+
{
90+
variant<int, int, float, std::string> v( in_place_index_t<0>{} );
91+
BOOST_TEST( holds_alternative<int>( v ) );
92+
BOOST_TEST( !holds_alternative<float>( v ) );
93+
BOOST_TEST( !holds_alternative<std::string>( v ) );
94+
}
95+
96+
{
97+
variant<int, int, float, std::string> v( in_place_index_t<1>{} );
98+
BOOST_TEST( holds_alternative<int>( v ) );
99+
BOOST_TEST( !holds_alternative<float>( v ) );
100+
BOOST_TEST( !holds_alternative<std::string>( v ) );
101+
}
102+
77103
return boost::report_errors();
78104
}

test/variant_holds_alternative_cx.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,20 @@ int main()
3939
{
4040
constexpr variant<int, float, float> v;
4141
STATIC_ASSERT( holds_alternative<int>( v ) );
42+
STATIC_ASSERT( !holds_alternative<float>( v ) );
4243
}
4344

4445
{
4546
constexpr variant<int, int, float> v( 3.14f );
47+
STATIC_ASSERT( !holds_alternative<int>( v ) );
4648
STATIC_ASSERT( holds_alternative<float>( v ) );
4749
}
50+
51+
{
52+
constexpr variant<int, int, float> v;
53+
STATIC_ASSERT( holds_alternative<int>( v ) );
54+
STATIC_ASSERT( !holds_alternative<float>( v ) );
55+
}
4856
}
4957

5058
#endif

0 commit comments

Comments
 (0)