christophe henry | 3 Jul 16:42
Picon

[Proto] Recreating an expression

Thanks Eric for your fast answer!
Unfortunately, this doesn't solve my problem. To make a very very long discussion long, here a small
example showing the problem from another side:
I have an expression wrapper called mp_terminal and I define terminals, but not in the documented
way (which I suspect is the problem) but instead deriving from them (for convenience purposes), for example:
struct True : mp_terminal<typename proto::terminal<guard_tag>::type>
{...}
These terminals are used with a simple grammar:
struct BuildGuards
   : proto::or_<
        proto::when<
                    proto::logical_or<BuildGuards,BuildGuards >,
                    GuardOR<BuildGuards(proto::_left),BuildGuards(proto::_right)>()
                >,
        proto::when<
                    proto::logical_and<BuildGuards,BuildGuards >,
                    GuardAND<BuildGuards(proto::_left),BuildGuards(proto::_right)>()
                >,
        proto::when<
                    proto::logical_not<BuildGuards >,
                    GuardNOT<BuildGuards(proto::_value)>()
                >,
         proto::when <
                    proto::terminal<guard_tag>,
                    proto::_()
  >
   >
{};
Then, expressions like:
True()|| False() give the expected result (struct GuardOR<struct True,struct False>).
Even True()&& (Dummy1() || !(False() || True())) give the expected result:
struct GuardAND<struct True,struct GuardOR<struct Dummy1,struct GuardNOT<struct GuardOR<struct False,struct True> > > >
But a "!" alone (meaning followed by just a terminal, not the other parts of the BuildGuards grammar) breaks all (as do all unary operators I tried), like !False() or True()|| !False().
!False() =>
struct GuardNOT<struct mp_terminal<struct boost::proto::exprns_::expr<struct boost::proto::tag::terminal,struct boost::proto::argsns_::term<struct guard_tag>,0> > >
 
Notice that !(False() || True()) works!
 
Now, if I do not derive from mp_terminal but instead proceed as documented, all works as expected:
proto::terminal<True>::type True_;
...
!False_ => correct result.
Sadly, this documented usage is unpractical in my use case.
So, supposing that I managed this easy grammar, I imagine that the usage I do of terminals (deriving from them) is not allowed.

Then, why do most use cases work like a charm? Only unary operators seem to fail.
 
Attached are 2 test files. V1 doesn't work in all cases while V2 does.
I use 1.38.
 
Thanks a lot!
 
Christophe

Windows Live™: Keep your life in sync. Check it out!
// TestProto.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <boost/proto/core.hpp>
#include <boost/proto/transform.hpp>

using namespace std;
namespace proto = boost::proto;

struct guard_tag{};

// grammar forbidding address of for terminals
struct terminal_grammar : 
		proto::not_<proto::address_of<proto::_> >
{};

// Forward-declare an expression wrapper
template<typename Expr>
struct mp_terminal;

struct sm_domain
	: proto::domain< proto::generator<mp_terminal>, terminal_grammar >
{};

template<typename Expr>
struct mp_terminal
	: proto::extends<Expr, mp_terminal<Expr>, sm_domain>
{
	typedef
		proto::extends<Expr, mp_terminal<Expr>, sm_domain>
		base_type;
	// Needs a constructor
	mp_terminal(Expr const &e = Expr())
		: base_type(e)
	{}
	// Unhide Proto's overloaded assignment operator
	using base_type::operator=;
};

template <class T1,class T2>
struct GuardOR 
{
    template <class FSM,class EVT,class SourceState,class TargetState>
    bool operator()(FSM& fsm,EVT const& evt,SourceState& src,TargetState& tgt)
    {
        return (T1()(fsm,evt,src,tgt) || T2()(fsm,evt,src,tgt));
    }
};
template <class T1,class T2>
struct GuardAND 
{
	template <class FSM,class EVT,class SourceState,class TargetState>
	bool operator()(FSM& fsm,EVT const& evt,SourceState& src,TargetState& tgt)
	{
		return (T1()(fsm,evt,src,tgt) && T2()(fsm,evt,src,tgt));
	}
};
template <class T1>
struct GuardNOT 
{
	template <class FSM,class EVT,class SourceState,class TargetState>
	bool operator()(FSM& fsm,EVT const& evt,SourceState& src,TargetState& tgt)
	{
		return !(T1()(fsm,evt,src,tgt));
	}
};

struct BuildGuards
   : proto::or_<
        proto::when<
                    proto::logical_or<BuildGuards,BuildGuards >,
                    GuardOR<BuildGuards(proto::_left),BuildGuards(proto::_right)>()
                >,
        proto::when<
                    proto::logical_and<BuildGuards,BuildGuards >,
                    GuardAND<BuildGuards(proto::_left),BuildGuards(proto::_right)>()
                >,
        proto::when<
                    proto::logical_not<BuildGuards >,
                    GuardNOT<BuildGuards(proto::_value)>()
                >,
         proto::when <
					proto::terminal<guard_tag>,
                    proto::_()
				>
   >
{};

struct True : mp_terminal<typename proto::terminal<guard_tag>::type>
{
	template <class T>
	bool operator()(T&)
	{
		std::cout << "always true" << std::endl;
		return true;
	}
};
struct False : mp_terminal<typename proto::terminal<guard_tag>::type>
{
	template <class T>
	bool operator()(T& )
	{
		std::cout << "always false" << std::endl;
		return false;
	}
};
struct Dummy1 : mp_terminal<typename proto::terminal<guard_tag>::type>
{
	template <class T>
	bool operator()(T& )
	{
		std::cout << "dummy" << std::endl;
		return true;
	}
};
template <class Expr>
void print_guard(Expr const& expr)
{
	cout << "in print_guard" << endl;
	cout << "matches:" << proto::matches<Expr,BuildGuards>::value << endl;
	typedef
		boost::result_of<BuildGuards(Expr)>::type
		result_type;
	cout << "result_type" << endl;
	cout << typeid(result_type).name() << endl;

	cout << "end print_guard" << endl;
}

int main()
{
	print_guard((True()&& Dummy1()));
	print_guard((True()|| False()));
	print_guard( ( True()&& (Dummy1() || !(False() || True())) ) );
	print_guard((True()|| !False()));
	print_guard( (!False()) );
    return 0;
}

// TestProto.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <boost/proto/core.hpp>
#include <boost/proto/transform.hpp>


using namespace std;
namespace proto = boost::proto;

struct guard_tag{};

// grammar forbidding address of for terminals
struct terminal_grammar : 
		proto::not_<proto::address_of<proto::_> >
{};

// Forward-declare an expression wrapper
template<typename Expr>
struct mp_terminal;

struct sm_domain
	: proto::domain< proto::generator<mp_terminal>, terminal_grammar >
{};

template<typename Expr>
struct mp_terminal
	: proto::extends<Expr, mp_terminal<Expr>, sm_domain>
{
	typedef
		proto::extends<Expr, mp_terminal<Expr>, sm_domain>
		base_type;
	// Needs a constructor
	mp_terminal(Expr const &e = Expr())
		: base_type(e)
	{}
	// Unhide Proto's overloaded assignment operator
	using base_type::operator=;
};

template <class T1,class T2>
struct GuardOR 
{
    template <class FSM,class EVT,class SourceState,class TargetState>
    bool operator()(FSM& fsm,EVT const& evt,SourceState& src,TargetState& tgt)
    {
        return (T1()(fsm,evt,src,tgt) || T2()(fsm,evt,src,tgt));
    }
};
template <class T1,class T2>
struct GuardAND 
{
	template <class FSM,class EVT,class SourceState,class TargetState>
	bool operator()(FSM& fsm,EVT const& evt,SourceState& src,TargetState& tgt)
	{
		return (T1()(fsm,evt,src,tgt) && T2()(fsm,evt,src,tgt));
	}
};
template <class T1>
struct GuardNOT 
{
	template <class FSM,class EVT,class SourceState,class TargetState>
	bool operator()(FSM& fsm,EVT const& evt,SourceState& src,TargetState& tgt)
	{
		return !(T1()(fsm,evt,src,tgt));
	}
};
struct BuildGuards
   : proto::or_<
        proto::when<
                    proto::logical_or<BuildGuards,BuildGuards >,
                    GuardOR<BuildGuards(proto::_left),BuildGuards(proto::_right)>()
                >,
        proto::when<
                    proto::logical_and<BuildGuards,BuildGuards >,
                    GuardAND<BuildGuards(proto::_left),BuildGuards(proto::_right)>()
                >,
        proto::when<
                    proto::logical_not<BuildGuards >,
                    GuardNOT<BuildGuards(proto::_value)>()
                >,
         proto::when <
					proto::terminal<proto::_>,
					proto::result_of::value<proto::_>()
				>
   >
{};

struct True
{
	template <class T>
	bool operator()(T&)
	{
		std::cout << "always true" << std::endl;
		return true;
	}
};
struct False
{
	template <class T>
	bool operator()(T& )
	{
		std::cout << "always false" << std::endl;
		return false;
	}
};
struct Dummy1
{
	template <class T>
	bool operator()(T& )
	{
		std::cout << "dummy" << std::endl;
		return true;
	}
};
template <class Expr>
void print_guard(Expr const& expr)
{
	cout << "in print_guard" << endl;
	cout << "matches:" << proto::matches<Expr,BuildGuards>::value << endl;
	typedef
		boost::result_of<BuildGuards(Expr)>::type
		result_type;
	cout << "result_type" << endl;
	cout << typeid(result_type).name() << endl;

	cout << "end print_guard" << endl;
}

int main()
{
	proto::terminal<True>::type True_;
	proto::terminal<False>::type False_;
	proto::terminal<Dummy1>::type Dummy1_;

	print_guard((True_&& Dummy1_));
	print_guard((True_|| False_));
	print_guard( ( True_&& (Dummy1_ || !(False_ || True_)) ) );
	print_guard((True_|| !False_));
	print_guard( (!False_) );
    return 0;
}

_______________________________________________
Boost-users mailing list
Boost-users <at> lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Gmane