|
6 | 6 |
|
7 | 7 | #include "invoke.hpp" |
8 | 8 |
|
9 | | -template<class Visitor, class Variant, class IndexSeq> |
10 | | -struct visit_return_type; |
11 | | - |
12 | | -template<class Visitor, class Variant, std::size_t... I> |
13 | | -struct visit_return_type<Visitor, Variant, std::index_sequence<I...>> { |
14 | | - using type = std::common_type_t<std::invoke_result_t< |
15 | | - Visitor, decltype(std::get<I>(std::declval<Variant>()))>...>; |
16 | | -}; |
17 | | - |
18 | 9 | template<class Visitor, class Variant> |
19 | 10 | constexpr decltype(auto) variant_visit(Visitor&& vis, Variant&& var) { |
20 | 11 | constexpr auto size = std::variant_size_v<std::decay_t<Variant>>; |
21 | | - using R = typename visit_return_type<Visitor&&, Variant&&, |
22 | | - std::make_index_sequence<size>>::type; |
23 | | - auto f = [&vis, &var, index = var.index()](auto&& self, auto i) -> R { |
24 | | - // [[assert: &self == &f]]; |
| 12 | + using R = std::invoke_result_t<Visitor, |
| 13 | + decltype(std::get<0>(std::declval<Variant>()))>; |
| 14 | + auto f = [&vis, &var, index = var.index()](auto&& rec, auto i) -> R { |
| 15 | + // [[assert: &rec == &f]]; |
25 | 16 | static_assert(0 <= i && i <= size); |
26 | | - if constexpr (decltype(i)::value == size) |
| 17 | + if constexpr (i == size) |
27 | 18 | throw std::bad_variant_access(); |
28 | | - else if (i == index) |
29 | | - return (invoke)(static_cast<Visitor&&>(vis), |
30 | | - std::get<i>(static_cast<Variant&&>(var))); |
31 | | - else |
32 | | - return self(self, std::integral_constant<std::size_t, i + 1>{}); |
33 | | - }; |
| 19 | + else { |
| 20 | + static_assert(std::is_same_v<R, std::invoke_result_t<Visitor, |
| 21 | + decltype(std::get<i>(std::declval<Variant>()))>>, |
| 22 | + "visitor must return the same type for all alternatives!"); |
| 23 | + if (i == index) |
| 24 | + return (invoke)(static_cast<Visitor&&>(vis), |
| 25 | + std::get<i>(static_cast<Variant&&>(var))); |
| 26 | + else |
| 27 | + return rec(rec, std::integral_constant<std::size_t, i + 1>{}); |
| 28 | + } |
| 29 | + }; |
34 | 30 | return f(f, std::integral_constant<std::size_t, 0>{}); |
35 | 31 | } |
36 | 32 |
|
|
0 commit comments