Boost logo

Boost :

Subject: Re: [boost] [proto] lazy functions in custom domains
From: Eric Niebler (eric_at_[hidden])
Date: 2009-02-23 06:43:42


Dean Michael Berris wrote:
> Hi Guys,
>
> I've recently tried to play around with Boost.Proto and I think I've
> run into a wall. I was trying to figure this (relatively simple) case
> out for a while already but it I'm at my wits end not seeing why the
> implementation doesn't work.
>
> I'm pasting the contents of the file (unmodified) which I've tried to
> follow from the Getting Started document. I was trying to get the
> custom domain approach working, but I never seem to get the lazy
> function to be called.
<snip>

Hi Dean,

You were /so/ close to getting this to work, but you would have had to
read more than the Getting Started guide. There is really only one error
in your code....

You create an expression extension with the BOOST_PROTO_EXTENDS() macro,
and then also define an operator() overload. BOOST_PROTO_EXTENDS()
defines operator() for you (check the docs) and the generated one is
being preferred to yours because it is a non-const member function. You
should use BOOST_PROTO_BASIC_EXTENDS() instead. Using proto::extends<>
also would have saved you this trouble.

There's one other minor issue: you're creating an expression with
proto::make_expr() but not specifying the domain. That's ok in this case
because Proto deduces your domain correctly, but in some cases it can't
so you should specify the domain.

The fixed code is below:

---->8--

#include <string>
#include <iostream>
#include <boost/cstdint.hpp>
#include <boost/proto/proto.hpp>
#include <vector>

namespace mpl = boost::mpl;
namespace fusion = boost::fusion;
namespace proto = boost::proto;

using proto::_;

using std::vector;
using std::cout;
using std::endl;
using boost::uint32_t;

struct user_tag;

template <class Tag>
struct placeholder {};

struct friendster_action_context
     : proto::callable_context<friendster_action_context const>
{
     uint32_t user_id;

     friendster_action_context(uint32_t id)
         : user_id(id)
     {}

     friendster_action_context(friendster_action_context const & other)
         : user_id(other.user_id)
     {}

     friendster_action_context & operator= (friendster_action_context
other) {
         other.swap(*this);
         return *this;
     }

     void swap(friendster_action_context & other) {
         std::swap(user_id, other.user_id);
     }

     typedef uint32_t result_type;

     result_type operator() (proto::tag::terminal,
placeholder<user_tag>) const {
         return this->user_id;
     }
};

template <class Expr>
struct friendster_action;

struct friendster_action_domain
     : proto::domain<proto::pod_generator<friendster_action> >
{};

template <class Expr>
struct friendster_action {
     BOOST_PROTO_BASIC_EXTENDS(
         Expr,
         friendster_action<Expr>,
         friendster_action_domain
     );

     typedef void result_type;

     result_type operator()(uint32_t const & id) const {
         friendster_action_context ctx(id);
         proto::eval(*this, ctx);
     }
};

friendster_action<proto::terminal<placeholder<user_tag> >::type> const
user = {{}};

struct friend_fun {
     typedef vector<uint32_t> result_type;
     template <class T>
     result_type operator() (T id) const {
         cout << "Getting the friends of user " << id << " ;)" << std::endl;
         return result_type();
     };
};

template <class Arg>
typename proto::result_of::make_expr<
     proto::tag::function,
     friendster_action_domain,
     friend_fun,
     typename proto::result_of::as_child<Arg const>::type
>::type
friends(Arg const & arg) {
     return proto::make_expr<
         proto::tag::function,
         friendster_action_domain
>(
         friend_fun(),
         proto::as_child(arg)
     );
}

#include <algorithm>

using namespace std;

int main(int argc, char * argv[]) {
     uint32_t users[] = { 1, 2, 3, 4 };
     uint32_t * begin = users;
     uint32_t * end = users + 4;
     cout << "Here they are: " << endl;
     for_each(begin, end, friends(user));
     string input;
     cin >> input;
     return 0;
}

---->8--

Hope this helps,

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk