On 3/30/2010 12:48 PM, Manjunath Kudlur wrote:
Thanks, Eric. That was an Ah-ha moment for me. I tried a different
variation of your program. I changed point to a templated
tuple and declared the terminals x and y with
proto::_ template arguments. Here is the complete program :
<snip>
Sorry for the delay. I've been away from my computer. This is indeed a
tricky problem. The trick is to realize that grammars can be made open
and extensible in a variety of ways. The simple is to define a
customization point. What you need is a way to plug into an existing
grammar new classes and members. Define a get_member_ptr template that
users of your grammar can use to make it aware of third-party types.
Code attached below:
#include <cassert>
#include <iostream>
#include
namespace proto = boost::proto;
using proto::_;
template<typename T>
struct type2type
{};
template<typename T>
struct tag
{};
template
struct get_mem_ptr;
struct get_mem_ptr_wrap : proto::callable
{
template<typename Sig>
struct result;
template
struct result
: boost::result_of()>
{};
template
typename boost::result_of()>::type
operator()(type2type<T>, tag<MemTag> const &) const
{
return get_mem_ptr()();
}
};
template
struct pair
{
X x;
Y y;
};
struct x_tag {};
struct y_tag {};
template
struct get_mem_ptr, x_tag>
{
typedef X pair::*result_type;
result_type operator()() const { return &pair::x; }
};
template
struct get_mem_ptr, y_tag>
{
typedef Y pair::*result_type;
result_type operator()() const { return &pair::y; }
};
proto::terminal >::type const x = {{}};
proto::terminal >::type const y = {{}};
struct arg_ {};
proto::terminal::type arg = {{}};
struct micro_lambda
: proto::or_<
proto::when<
proto::mem_ptr<_, proto::terminal > >
, micro_lambda(
proto::_make_mem_ptr(
proto::_left
, proto::_make_terminal(
get_mem_ptr_wrap(
type2type()
, proto::_value(proto::_right)
)
)
)
)
>
, proto::when<
proto::terminal
, proto::_state
>
, proto::otherwise<
proto::_default
>
>
{} eval;
int main()
{
pair p = {2,4.f};
float r = eval( arg->*x + arg->*y, p );
assert( r == p.x + p.y );
std::cout << r << std::endl;
eval( arg->*x *= 21, p );
assert( p.x == 42 );
std::cout << p.x << std::endl;
}
Note that the x and y globals are no longer raw member pointer terminals
but tags. The grammar recognizes tags and uses them to look up the
actual member pointer. It also needs to know the class type, so that is
calculated and also passed along.
This code runs compiles and runs fine with gcc. Msvc doesn't like it.
But maybe you can sort that out.
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com