[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