• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright Louis Dionne 2013-2017
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>
__anon3b9cee7c0102(auto f) 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>
process(Any &,std::type_index const &,Default & 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>
process(Any & a,std::type_index const & t,Default & default_,Case & case_,Rest &...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>
switch_(Any & a)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 
main()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 }
106