1 | /* |
2 | * Copyright 2017-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <type_traits> |
20 | #include <utility> |
21 | |
22 | /** |
23 | * folly implementation of `std::overload` like functionality |
24 | * |
25 | * Example: |
26 | * struct One {}; |
27 | * struct Two {}; |
28 | * boost::variant<One, Two> value; |
29 | * |
30 | * variant_match(value, |
31 | * [] (const One& one) { ... }, |
32 | * [] (const Two& two) { ... }); |
33 | */ |
34 | |
35 | namespace folly { |
36 | |
37 | namespace detail { |
38 | template <typename...> |
39 | struct Overload; |
40 | |
41 | template <typename Case, typename... Cases> |
42 | struct Overload<Case, Cases...> : Overload<Cases...>, Case { |
43 | Overload(Case c, Cases... cs) |
44 | : Overload<Cases...>(std::move(cs)...), Case(std::move(c)) {} |
45 | |
46 | using Case::operator(); |
47 | using Overload<Cases...>::operator(); |
48 | }; |
49 | |
50 | template <typename Case> |
51 | struct Overload<Case> : Case { |
52 | explicit Overload(Case c) : Case(std::move(c)) {} |
53 | |
54 | using Case::operator(); |
55 | }; |
56 | } // namespace detail |
57 | |
58 | /* |
59 | * Combine multiple `Cases` in one function object |
60 | */ |
61 | template <typename... Cases> |
62 | decltype(auto) overload(Cases&&... cases) { |
63 | return detail::Overload<typename std::decay<Cases>::type...>{ |
64 | std::forward<Cases>(cases)...}; |
65 | } |
66 | |
67 | /* |
68 | * Match `Variant` with one of the `Cases` |
69 | * |
70 | * Note: you can also use `[] (const auto&) {...}` as default case |
71 | * |
72 | */ |
73 | template <typename Variant, typename... Cases> |
74 | decltype(auto) variant_match(Variant&& variant, Cases&&... cases) { |
75 | return apply_visitor( |
76 | overload(std::forward<Cases>(cases)...), std::forward<Variant>(variant)); |
77 | } |
78 | |
79 | } // namespace folly |
80 | |