]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // Copyright Louis Dionne 2013-2017 |
7c673cae FG |
2 | // Distributed under the Boost Software License, Version 1.0. |
3 | // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) | |
4 | ||
5 | // Make sure `assert` always triggers an assertion | |
6 | #ifdef NDEBUG | |
7 | # undef NDEBUG | |
8 | #endif | |
9 | ||
10 | //! [full] | |
11 | #include <boost/hana.hpp> | |
12 | ||
13 | #include <boost/any.hpp> | |
14 | #include <cassert> | |
15 | #include <string> | |
16 | #include <typeindex> | |
17 | #include <typeinfo> | |
18 | #include <utility> | |
19 | namespace hana = boost::hana; | |
20 | ||
21 | //! [cases] | |
22 | template <typename T> | |
23 | auto case_ = [](auto f) { | |
24 | return hana::make_pair(hana::type_c<T>, f); | |
25 | }; | |
26 | ||
27 | struct default_t; | |
28 | auto default_ = case_<default_t>; | |
29 | //! [cases] | |
30 | ||
31 | //! [process] | |
32 | template <typename Any, typename Default> | |
33 | auto process(Any&, std::type_index const&, Default& default_) { | |
34 | return default_(); | |
35 | } | |
36 | ||
37 | template <typename Any, typename Default, typename Case, typename ...Rest> | |
38 | auto process(Any& a, std::type_index const& t, Default& default_, | |
39 | Case& case_, Rest& ...rest) | |
40 | { | |
41 | using T = typename decltype(+hana::first(case_))::type; | |
42 | return t == typeid(T) ? hana::second(case_)(*boost::unsafe_any_cast<T>(&a)) | |
43 | : process(a, t, default_, rest...); | |
44 | } | |
45 | //! [process] | |
46 | ||
47 | //! [switch_] | |
48 | template <typename Any> | |
49 | auto switch_(Any& a) { | |
50 | return [&a](auto ...cases_) { | |
51 | auto cases = hana::make_tuple(cases_...); | |
52 | ||
53 | auto default_ = hana::find_if(cases, [](auto const& c) { | |
54 | return hana::first(c) == hana::type_c<default_t>; | |
55 | }); | |
56 | static_assert(default_ != hana::nothing, | |
57 | "switch is missing a default_ case"); | |
58 | ||
59 | auto rest = hana::filter(cases, [](auto const& c) { | |
60 | return hana::first(c) != hana::type_c<default_t>; | |
61 | }); | |
62 | ||
63 | return hana::unpack(rest, [&](auto& ...rest) { | |
64 | return process(a, a.type(), hana::second(*default_), rest...); | |
65 | }); | |
66 | }; | |
67 | } | |
68 | //! [switch_] | |
69 | //! [full] | |
70 | ||
71 | ||
72 | int main() { | |
73 | using namespace std::literals; | |
74 | ||
75 | { | |
76 | ||
77 | //! [usage] | |
78 | boost::any a = 'x'; | |
79 | std::string r = switch_(a)( | |
80 | case_<int>([](auto i) { return "int: "s + std::to_string(i); }), | |
81 | case_<char>([](auto c) { return "char: "s + std::string{c}; }), | |
82 | default_([] { return "unknown"s; }) | |
83 | ); | |
84 | ||
85 | assert(r == "char: x"s); | |
86 | //! [usage] | |
87 | ||
88 | }{ | |
89 | ||
90 | //! [result_inference] | |
91 | boost::any a = 'x'; | |
92 | auto r = switch_(a)( | |
93 | case_<int>([](auto) -> int { return 1; }), | |
94 | case_<char>([](auto) -> long { return 2l; }), | |
95 | default_([]() -> long long { return 3ll; }) | |
96 | ); | |
97 | ||
98 | // r is inferred to be a long long | |
99 | static_assert(std::is_same<decltype(r), long long>{}, ""); | |
100 | assert(r == 2ll); | |
101 | //! [result_inference] | |
102 | ||
103 | } | |
104 | ||
105 | } |