1 // Boost.TypeErasure library
2 //
3 // Copyright 2011 Steven Watanabe
4 //
5 // Distributed under the Boost Software License Version 1.0. (See
6 // accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // $Id$
10
11 //[multifunction
12 /*`
13 (For the source of this example see
14 [@boost:/libs/type_erasure/example/multifunction.cpp multifunction.cpp])
15
16 This example implements an extension of Boost.Function that supports
17 multiple signatures.
18
19 [note This example uses C++11 features. You'll need a
20 recent compiler for it to work.]
21 */
22
23 #include <boost/type_erasure/any.hpp>
24 #include <boost/type_erasure/builtin.hpp>
25 #include <boost/type_erasure/callable.hpp>
26 #include <boost/mpl/vector.hpp>
27 #include <boost/variant.hpp>
28 #include <boost/phoenix/core.hpp>
29 #include <boost/phoenix/operator.hpp>
30 #include <boost/range/algorithm.hpp>
31 #include <algorithm>
32 #include <vector>
33 #include <string>
34 #include <iostream>
35
36 namespace mpl = boost::mpl;
37 using namespace boost::type_erasure;
38 namespace phoenix = boost::phoenix;
39
40 // First of all we'll declare the multifunction template.
41 // multifunction is like Boost.Function but instead of
42 // taking one signature, it takes any number of them.
43 template<class... Sig>
44 using multifunction =
45 any<
46 mpl::vector<
47 copy_constructible<>,
48 typeid_<>,
49 relaxed,
50 callable<Sig>...
51 >
52 >;
53
54 // Let's use multifunction to process a variant. We'll start
55 // by defining a simple recursive variant to use.
56 typedef boost::make_recursive_variant<
57 int,
58 double,
59 std::string,
60 std::vector<boost::recursive_variant_> >::type variant_type;
61 typedef std::vector<variant_type> vector_type;
62
63 // Now we'll define a multifunction that can operate
64 // on the leaf nodes of the variant.
65 typedef multifunction<void(int), void(double), void(std::string)> function_type;
66
67 class variant_handler
68 {
69 public:
handle(const variant_type & arg)70 void handle(const variant_type& arg)
71 {
72 boost::apply_visitor(impl, arg);
73 }
set_handler(function_type f)74 void set_handler(function_type f)
75 {
76 impl.f = f;
77 }
78 private:
79 // A class that works with boost::apply_visitor
80 struct dispatcher : boost::static_visitor<void>
81 {
82 // used for the leaves
83 template<class T>
operator ()variant_handler::dispatcher84 void operator()(const T& t) { f(t); }
85 // For a vector, we recursively operate on the elements
operator ()variant_handler::dispatcher86 void operator()(const vector_type& v)
87 {
88 boost::for_each(v, boost::apply_visitor(*this));
89 }
90 function_type f;
91 };
92 dispatcher impl;
93 };
94
main()95 int main() {
96 variant_handler x;
97 x.set_handler(std::cout << phoenix::val("Value: ") << phoenix::placeholders::_1 << std::endl);
98
99 x.handle(1);
100 x.handle(2.718);
101 x.handle("The quick brown fox jumps over the lazy dog.");
102 x.handle(vector_type{ 1.618, "Gallia est omnis divisa in partes tres", 42 });
103 }
104
105 //]
106