1[/============================================================================== 2 Copyright (C) 2001-2010 Joel de Guzman 3 Copyright (C) 2001-2005 Dan Marsden 4 Copyright (C) 2001-2010 Thomas Heller 5 6 Distributed under the Boost Software License, Version 1.0. (See accompanying 7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8===============================================================================/] 9 10[section Extending Actors] 11 12[link phoenix.inside.actor Actors] are one of the main parts of the 13library, and one of the many customization points. The default actor implementation 14provides several operator() overloads which deal with the evaluation of expressions. 15 16For some use cases this might not be enough. For convenience it is thinkable to 17provide custom member functions which generate new expressions. An example is the 18[link phoenix.modules.statement.___if_else_____statement '''if_else_''' 19Statement] which provides an additional else member for generating a lazy if-else 20expression. With this the actual Phoenix expression becomes more expressive. 21 22Another scenario is to give actors the semantics of a certain well known interface 23or concept. This tutorial like section will provide information on how to implement 24a custom actor which is usable as if it were a 25[@http://www.sgi.com/tech/stl/Container.html STL Container]. 26 27[heading Requirements] 28 29Let's repeat what we want to have: 30 31[table 32 [[Expression] [Semantics]] 33 [[`a.begin()`] [Returns an iterator pointing to the first element in the container.]] 34 [[`a.end()`] [Returns an iterator pointing one past the last element in the container.]] 35 [[`a.size()`] [Returns the size of the container, that is, its number of elements.]] 36 [[`a.max_size()`] [Returns the largest size that this container can ever have.]] 37 [[`a.empty()`] [Equivalent to a.size() == 0. (But possibly faster.)]] 38 [[`a.swap(b)`] [Equivalent to swap(a,b)]] 39] 40 41Additionally, we want all the operator() overloads of the regular actor. 42 43[heading Defining the actor] 44 45The first version of our `container_actor` interface will show the general 46principle. This will be continually extended. For the sake of simplicity, 47every member function generator will return [link phoenix.modules.core.nothing `nothing`] 48at first. 49 50 template <typename Expr> 51 struct container_actor 52 : actor<Expr> 53 { 54 typedef actor<Expr> base_type; 55 typedef container_actor<Expr> that_type; 56 57 container_actor( base_type const& base ) 58 : base_type( base ) {} 59 60 expression::null<mpl::void_>::type const begin() const { return nothing; } 61 expression::null<mpl::void_>::type const end() const { return nothing; } 62 expression::null<mpl::void_>::type const size() const { return nothing; } 63 expression::null<mpl::void_>::type const max_size() const { return nothing; } 64 expression::null<mpl::void_>::type const empty() const { return nothing; } 65 66 // Note that swap is the only function needing another container. 67 template <typename Container> 68 expression::null<mpl::void_>::type const swap( actor<Container> const& ) const { return nothing; } 69 }; 70 71[heading Using the actor] 72 73Although the member functions do nothing right now, we want to test if we can use 74our new actor. 75 76First, lets create a generator which wraps the `container_actor` around any other 77expression: 78 79 template <typename Expr> 80 container_actor<Expr> const 81 container( actor<Expr> const& expr ) 82 { 83 return expr; 84 } 85 86Now let's test this: 87 88 std::vector<int> v; 89 v.push_back(0); 90 v.push_back(1); 91 v.push_back(2); 92 v.push_back(3); 93 94 (container(arg1).size())(v); 95 96Granted, this is not really elegant and not very practical (we could have just 97used phoenix::begin(v) from the [link phoenix.modules.stl.algorithm Phoenix algorithm module], 98but we can do better. 99 100Let's have an [link phoenix.modules.core.arguments argument placeholder] 101which is usable as if it was a STL container: 102 103 container_actor<expression::argument<1>::type> const con1; 104 // and so on ... 105 106The above example can be rewritten as: 107 108 std::vector<int> v; 109 v.push_back(0); 110 v.push_back(1); 111 v.push_back(2); 112 v.push_back(3); 113 114 (con1.size())(v); 115 116Wow, that was easy! 117 118[heading Adding life to the actor] 119 120This one will be even easier! 121 122First, we define a [link phoenix.modules.function lazy function] which 123evaluates the expression we want to implement. 124Following is the implementation of the size function: 125 126 struct size_impl 127 { 128 // result_of protocol: 129 template <typename Sig> 130 struct result; 131 132 template <typename This, typename Container> 133 struct result<This(Container)> 134 { 135 // Note, remove reference here, because Container can be anything 136 typedef typename boost::remove_reference<Container>::type container_type; 137 138 // The result will be size_type 139 typedef typename container_type::size_type type; 140 }; 141 142 template <typename Container> 143 typename result<size_impl(Container const&)>::type 144 operator()(Container const& container) const 145 { 146 return container.size(); 147 } 148 }; 149 150Good, this was the first part. The second part will be to implement the size member 151function of `container_actor`: 152 153 template <typename Expr> 154 struct container_actor 155 : actor<Expr> 156 { 157 typedef actor<Expr> base_type; 158 typedef container_actor<Expr> that_type; 159 160 container_actor( base_type const& base ) 161 : base_type( base ) {} 162 163 typename expression::function<size_impl, that_type>::type const 164 size() const 165 { 166 function<size_impl> const f = size_impl(); 167 return f(*this); 168 } 169 170 // the rest ... 171 }; 172 173It is left as an exercise to the user to implement the missing parts by reusing 174functions from the [link phoenix.modules.stl.algorithm Phoenix Algorithm Module] 175(the impatient take a look here: [@../../example/container_actor.cpp container_actor.cpp]). 176 177[endsect] 178