[proto] lazy functions in custom domains

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. The expected result from the code below would be to have multiple lines of output that says "Getting the friends of user # ;)" but I don't see those. There are no compilation errors, and I don't see anything obviously wrong from the implementation and how I understand Lazy functions. I'm just not sure about how lazy functions though can be made part of a domain though -- didn't find anything in the Getting Started guide about it. Help would be very much appreciated (BTW I'm using Proto that's in Boost 1.38.0, building with GCC 4.0 in Mac OSX 10.5.6): ---->8-- #include <iostream> #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; 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_EXTENDS(Expr, friendster_action<Expr>, friendster_action_domain); typedef void result_type; result_type operator()(uint32_t id) const { friendster_action_context ctx; ctx.user_id = id; return 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, friend_fun, typename proto::result_of::as_child<Arg const>::type
::type friends(Arg const & arg) { return proto::make_expr<proto::tag::function>( 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-- -- Dean Michael Berris | Software Engineer, Friendster, Inc. blog.cplusplus-soup.com | twitter.com/mikhailberis | linkedin.com/in/mikhailberis | profiles.friendster.com/mikhailberis | deanberris.com

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

On Mon, Feb 23, 2009 at 7:43 PM, Eric Niebler <eric@boost-consulting.com> wrote:
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....
Yup, I really should read more of the documentation in a room where I can focus 100%. ;-)
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.
Ah, that makes sense. :-)
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--
[snip]
---->8--
Hope this helps,
Oh my, that was quick. Thanks Eric, it does work! Now on to fleshing out that DSEL... ;-) -- Dean Michael Berris | Software Engineer, Friendster, Inc. blog.cplusplus-soup.com | twitter.com/mikhailberis | linkedin.com/in/mikhailberis | profiles.friendster.com/mikhailberis | deanberris.com
participants (2)
-
Dean Michael Berris
-
Eric Niebler