{
namespace __variant
{
- // Returns the first apparence of _Tp in _Types.
+ // Returns the first appearence of _Tp in _Types.
// Returns sizeof...(_Types) if _Tp is not in _Types.
template<typename _Tp, typename... _Types>
struct __index_of : std::integral_constant<size_t, 0> {};
inline constexpr bool __exactly_once =
__tuple_count_v<_Tp, tuple<_Types...>> == 1;
- // Takes _Types and create an overloaded _S_fun for each type.
- // If a type appears more than once in _Types, create only one overload.
- template<typename... _Types>
- struct __overload_set
- { static void _S_fun(); };
+ // Helper used to check for valid conversions that don't involve narrowing.
+ template<typename _Ti> struct _Arr { _Ti _M_x[1]; };
- template<typename _First, typename... _Rest>
- struct __overload_set<_First, _Rest...> : __overload_set<_Rest...>
+ // Build an imaginary function FUN(Ti) for each alternative type Ti
+ template<size_t _Ind, typename _Tp, typename _Ti,
+ bool _Ti_is_cv_bool = is_same_v<remove_cv_t<_Ti>, bool>,
+ typename = void>
+ struct _Build_FUN
{
- using __overload_set<_Rest...>::_S_fun;
- static integral_constant<size_t, sizeof...(_Rest)> _S_fun(_First);
+ // This function means 'using _Build_FUN<I, T, Ti>::_S_fun;' is valid,
+ // but only static functions will be considered in the call below.
+ void _S_fun();
};
- template<typename... _Rest>
- struct __overload_set<void, _Rest...> : __overload_set<_Rest...>
+ // ... for which Ti x[] = {std::forward<T>(t)}; is well-formed,
+ template<size_t _Ind, typename _Tp, typename _Ti>
+ struct _Build_FUN<_Ind, _Tp, _Ti, false,
+ void_t<decltype(_Arr<_Ti>{{std::declval<_Tp>()}})>>
{
- using __overload_set<_Rest...>::_S_fun;
+ // This is the FUN function for type _Ti, with index _Ind
+ static integral_constant<size_t, _Ind> _S_fun(_Ti);
};
- // Helper for variant(_Tp&&) and variant::operator=(_Tp&&).
- // __accepted_index maps an arbitrary _Tp to an alternative type in _Variant
- // (or to variant_npos).
- template<typename _Tp, typename _Variant, typename = void>
- struct __accepted_index
- { static constexpr size_t value = variant_npos; };
+ // ... and if Ti is cv bool, remove_cvref_t<T> is bool.
+ template<size_t _Ind, typename _Tp, typename _Ti>
+ struct _Build_FUN<_Ind, _Tp, _Ti, true,
+ enable_if_t<is_same_v<__remove_cvref_t<_Tp>, bool>>>
+ {
+ // This is the FUN function for when _Ti is cv bool, with index _Ind
+ static integral_constant<size_t, _Ind> _S_fun(_Ti);
+ };
- template<typename _Tp, typename... _Types>
- struct __accepted_index<
- _Tp, variant<_Types...>,
- void_t<decltype(__overload_set<_Types...>::_S_fun(std::declval<_Tp>()))>>
+ template<typename _Tp, typename _Variant,
+ typename = make_index_sequence<variant_size_v<_Variant>>>
+ struct _Build_FUNs;
+
+ template<typename _Tp, typename... _Ti, size_t... _Ind>
+ struct _Build_FUNs<_Tp, variant<_Ti...>, index_sequence<_Ind...>>
+ : _Build_FUN<_Ind, _Tp, _Ti>...
{
- static constexpr size_t value = sizeof...(_Types) - 1
- - decltype(__overload_set<_Types...>::
- _S_fun(std::declval<_Tp>()))::value;
+ using _Build_FUN<_Ind, _Tp, _Ti>::_S_fun...;
};
+ // The index j of the overload FUN(Tj) selected by overload resolution
+ // for FUN(std::forward<_Tp>(t))
+ template<typename _Tp, typename _Variant>
+ using _FUN_type
+ = decltype(_Build_FUNs<_Tp, _Variant>::_S_fun(std::declval<_Tp>()));
+
+ // The index selected for FUN(std::forward<T>(t)), or variant_npos if none.
+ template<typename _Tp, typename _Variant, typename = void>
+ struct __accepted_index
+ : integral_constant<size_t, variant_npos>
+ { };
+
+ template<typename _Tp, typename _Variant>
+ struct __accepted_index<_Tp, _Variant, void_t<_FUN_type<_Tp, _Variant>>>
+ : _FUN_type<_Tp, _Variant>
+ { };
+
// Returns the raw storage for __v.
template<typename _Variant>
void* __get_storage(_Variant&& __v) noexcept
__exactly_once = __detail::__variant::__exactly_once<_Tp, _Types...>;
template<typename _Tp>
- static constexpr size_t __accepted_index =
- __detail::__variant::__accepted_index<_Tp&&, variant>::value;
+ static constexpr size_t __accepted_index
+ = __detail::__variant::__accepted_index<_Tp, variant>::value;
template<size_t _Np, typename = enable_if_t<(_Np < sizeof...(_Types))>>
using __to_type = variant_alternative_t<_Np, variant>;
constexpr
variant(_Tp&& __t)
noexcept(is_nothrow_constructible_v<_Tj, _Tp>)
- : variant(in_place_index<__accepted_index<_Tp&&>>,
+ : variant(in_place_index<__accepted_index<_Tp>>,
std::forward<_Tp>(__t))
{ }
noexcept(is_nothrow_assignable_v<__accepted_type<_Tp&&>&, _Tp>
&& is_nothrow_constructible_v<__accepted_type<_Tp&&>, _Tp>)
{
- constexpr auto __index = __accepted_index<_Tp&&>;
+ constexpr auto __index = __accepted_index<_Tp>;
if (index() == __index)
std::get<__index>(*this) = std::forward<_Tp>(__rhs);
else
variant<int, string> v("a");
VERIFY(holds_alternative<string>(v));
VERIFY(get<1>(v) == "a");
+
+ {
+ // P0608R3
+ variant<string, bool> x = "abc";
+ VERIFY(x.index() == 0);
+ }
+
+ {
+ // P0608R3
+ struct U {
+ U(char16_t c) : c(c) { }
+ char16_t c;
+ };
+ variant<char, U> x = u'\u2043';
+ VERIFY(x.index() == 1);
+ VERIFY(std::get<1>(x).c == u'\u2043');
+
+ struct Double {
+ Double(double& d) : d(d) { }
+ double& d;
+ };
+ double d = 3.14;
+ variant<int, Double> y = d;
+ VERIFY(y.index() == 1);
+ VERIFY(std::get<1>(y).d == d);
+ }
}
struct ThrowingMoveCtorThrowsCopyCtor
VERIFY(holds_alternative<string>(variant<int, string>("a")));
VERIFY(get<1>(v) == "a");
+
+ {
+ // P0608R3
+ using T1 = variant<float, int>;
+ T1 v1;
+ v1 = 0;
+ VERIFY(v1.index() == 1);
+
+ using T2 = variant<float, long>;
+ T2 v2;
+ v2 = 0;
+ VERIFY(v2.index() == 1);
+
+ struct big_int {
+ big_int(int) { }
+ };
+ using T3 = variant<float, big_int>;
+ T3 v3;
+ v3 = 0;
+ VERIFY(v3.index() == 1);
+ }
}
void dtor()