a3e1c883b1
- merged V3 into trunk. - some minor fixes regarding result type calculation [SVN r69826]
178 lines
5.6 KiB
Plaintext
178 lines
5.6 KiB
Plaintext
[/==============================================================================
|
|
Copyright (C) 2001-2010 Joel de Guzman
|
|
Copyright (C) 2001-2005 Dan Marsden
|
|
Copyright (C) 2001-2010 Thomas Heller
|
|
|
|
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
===============================================================================/]
|
|
|
|
[section Extending Actors]
|
|
|
|
[link phoenix.inside.actor Actors] are one of the main parts of the
|
|
library, and one of the many customization points. The default actor implementation
|
|
provides several operator() overloads which deal with the evaluation of expressions.
|
|
|
|
For some use cases this might not be enough. For convenience it is thinkable to
|
|
provide custom member functions which generate new expressions. An example is the
|
|
[link phoenix.modules.statement.___if_else_____statement '''if_else_'''
|
|
Statement] which provides an additional else member for generating a lazy if-else
|
|
expression. With this the actual Phoenix expression becomes more expressive.
|
|
|
|
Another scenario is to give actors the semantics of a certain well known interface
|
|
or concept. This tutorial like section will provide information on how to implement
|
|
a custom actor which is usable as if it were a
|
|
[@http://www.sgi.com/tech/stl/Container.html STL Container].
|
|
|
|
[heading Requirements]
|
|
|
|
Let's repeat what we want to have:
|
|
|
|
[table
|
|
[[Expression] [Semantics]]
|
|
[[`a.begin()`] [Returns an iterator pointing to the first element in the container.]]
|
|
[[`a.end()`] [Returns an iterator pointing one past the last element in the container.]]
|
|
[[`a.size()`] [Returns the size of the container, that is, its number of elements.]]
|
|
[[`a.max_size()`] [Returns the largest size that this container can ever have.]]
|
|
[[`a.empty()`] [Equivalent to a.size() == 0. (But possibly faster.)]]
|
|
[[`a.swap(b)`] [Equivalent to swap(a,b)]]
|
|
]
|
|
|
|
Additionally, we want all the operator() overloads of the regular actor.
|
|
|
|
[heading Defining the actor]
|
|
|
|
The first version of our `container_actor` interface will show the general
|
|
principle. This will be continually extended. For the sake of simplicity,
|
|
every member function generator will return [link phoenix.modules.core.nothing `nothing`]
|
|
at first.
|
|
|
|
template <typename Expr>
|
|
struct container_actor
|
|
: actor<Expr>
|
|
{
|
|
typedef actor<Expr> base_type;
|
|
typedef container_actor<Expr> that_type;
|
|
|
|
container_actor( base_type const& base )
|
|
: base_type( base ) {}
|
|
|
|
expression::null<mpl::void_>::type const begin() const { return nothing; }
|
|
expression::null<mpl::void_>::type const end() const { return nothing; }
|
|
expression::null<mpl::void_>::type const size() const { return nothing; }
|
|
expression::null<mpl::void_>::type const max_size() const { return nothing; }
|
|
expression::null<mpl::void_>::type const empty() const { return nothing; }
|
|
|
|
// Note that swap is the only function needing another container.
|
|
template <typename Container>
|
|
expression::null<mpl::void_>::type const swap( actor<Container> const& ) const { return nothing; }
|
|
};
|
|
|
|
[heading Using the actor]
|
|
|
|
Although the member functions do nothing right now, we want to test if we can use
|
|
our new actor.
|
|
|
|
First, lets create a generator which wraps the `container_actor` around any other
|
|
expression:
|
|
|
|
template <typename Expr>
|
|
container_actor<Expr> const
|
|
container( actor<Expr> const& expr )
|
|
{
|
|
return expr;
|
|
}
|
|
|
|
Now let's test this:
|
|
|
|
std::vector<int> v;
|
|
v.push_back(0);
|
|
v.push_back(1);
|
|
v.push_back(2);
|
|
v.push_back(3);
|
|
|
|
(container(arg1).size())(v);
|
|
|
|
Granted, this is not really elegant and not very practical (we could have just
|
|
used phoenix::begin(v) from the [link phoenix.modules.stl.algorithm Phoenix algorithm module],
|
|
but we can do better.
|
|
|
|
Let's have an [link phoenix.modules.core.arguments argument placeholder]
|
|
which is usable as if it was a STL container:
|
|
|
|
container_actor<expression::argument<1>::type> const con1;
|
|
// and so on ...
|
|
|
|
The above example can be rewritten as:
|
|
|
|
std::vector<int> v;
|
|
v.push_back(0);
|
|
v.push_back(1);
|
|
v.push_back(2);
|
|
v.push_back(3);
|
|
|
|
(con1.size())(v);
|
|
|
|
Wow, that was easy!
|
|
|
|
[heading Adding life to the actor]
|
|
|
|
This one will be even easier!
|
|
|
|
First, we define a [link phoenix.modules.function lazy function] which
|
|
evaluates the expression we want to implement.
|
|
Following is the implementation of the size function:
|
|
|
|
struct size_impl
|
|
{
|
|
// result_of protocol:
|
|
template <typename Sig>
|
|
struct result;
|
|
|
|
template <typename This, typename Container>
|
|
struct result<This(Container)>
|
|
{
|
|
// Note, remove reference here, because Container can be anything
|
|
typedef typename boost::remove_reference<Container>::type container_type;
|
|
|
|
// The result will be size_type
|
|
typedef typename container_type::size_type type;
|
|
};
|
|
|
|
template <typename Container>
|
|
typename result<size_impl(Container const&)>::type
|
|
operator()(Container const& container) const
|
|
{
|
|
return container.size();
|
|
}
|
|
};
|
|
|
|
Good, this was the first part. The second part will be to implement the size member
|
|
function of `container_actor`:
|
|
|
|
template <typename Expr>
|
|
struct container_actor
|
|
: actor<Expr>
|
|
{
|
|
typedef actor<Expr> base_type;
|
|
typedef container_actor<Expr> that_type;
|
|
|
|
container_actor( base_type const& base )
|
|
: base_type( base ) {}
|
|
|
|
typename expression::function<size_impl, that_type>::type const
|
|
size() const
|
|
{
|
|
function<size_impl> const f = size_impl();
|
|
return f(*this);
|
|
}
|
|
|
|
// the rest ...
|
|
};
|
|
|
|
It is left as an exercise to the user to implement the missing parts by reusing
|
|
functions from the [link phoenix.modules.stl.algorithm Phoenix Algorithm Module]
|
|
(the impatient take a look here: [@../../example/container_actor.cpp container_actor.cpp]).
|
|
|
|
[endsect]
|