[Proto] Strange behavior with semantic action and custom tag function
I'm stuck on some problem that may en dup silly. I have a DSL defined by the following grammar : struct dimen_grammar : bp::or_< ////////////////////////////////////////////////////////////////////////// // Terminals are dimensional values or integral values ////////////////////////////////////////////////////////////////////////// bp::or_< bp::terminal< dimensions<bp::_,bp::_> > , integer_grammar > ////////////////////////////////////////////////////////////////////////// // dimen can be added together or scaled by an integer // or shifted left or right by an integer ////////////////////////////////////////////////////////////////////////// ,bp::or_< bp::plus<dimen_grammar,dimen_grammar> ,bp::multiplies<dimen_grammar,integer_grammar> ,bp::multiplies<integer_grammar,dimen_grammar> ,bp::shift_left<dimen_grammar,integer_grammar> ,bp::shift_right<dimen_grammar,integer_grammar> > > {}; I've defined a proper callable_context that take care of my special terminals and built a terminal class. At this point, everythign works perfect : i can build expressions and evaluate them. Now I add a grammar with semantic action that helps me computes an aspect of those expression : struct dimen_size : bp::or_< ////////////////////////////////////////////////////////////////////////// // dimensionnal values terminal contains its own size value ////////////////////////////////////////////////////////////////////////// bp::when< bp::terminal< dimensions<bp::_,bp::_> > , dimension_of< bp::_value>() > ////////////////////////////////////////////////////////////////////////// // integral values has a size of 1 ////////////////////////////////////////////////////////////////////////// , bp::when<integer_grammar, bm::size_t<1>()> ////////////////////////////////////////////////////////////////////////// // size(d1+d2) = max(size(d1),size(d2)) ////////////////////////////////////////////////////////////////////////// , bp::when< bp::plus<dimen_grammar,dimen_grammar> , bm::max<dimen_size(bp::_left),dimen_size(bp::_right)>() > ////////////////////////////////////////////////////////////////////////// // size(d1*i) = size(d1) ////////////////////////////////////////////////////////////////////////// , bp::when< bp::multiplies<dimen_grammar,integer_grammar> , dimen_size(bp::_left) > ////////////////////////////////////////////////////////////////////////// // size(i*d2) = size(d2) ////////////////////////////////////////////////////////////////////////// , bp::when< bp::multiplies<integer_grammar,dimen_grammar> , dimen_size(bp::_right) > ////////////////////////////////////////////////////////////////////////// // size(d1<<i) = size(d1) ////////////////////////////////////////////////////////////////////////// , bp::when< bp::shift_left<dimen_grammar,integer_grammar> , dimen_size(bp::_left) > ////////////////////////////////////////////////////////////////////////// // size(d1>>i) = size(d1) ////////////////////////////////////////////////////////////////////////// , bp::when< bp::shift_right<dimen_grammar,integer_grammar> , dimen_size(bp::_left) > ////////////////////////////////////////////////////////////////////////// // Other returns 0 ////////////////////////////////////////////////////////////////////////// , bp::when<bp::_, bm::size_t<0>()> > {}; This works. If I remove the bp::when<bp::_, bm::size_t<0>()>, it fails to compile when I try to use a hand-overloaded operator<< for displaying expression values on standard output. So, is there anything I missed (like deactivating operator<< in the grammar somehow ?) ? Other question : When defining custom tag to build new function, why does the make_expr tempalte doesn't do check on its argument to see if it's match the grammar of the domain it's bound to use ? Seems I'm forced to add additional layer of SFINAE to prevent those function to get called on w/e types. Thanks in advance for help -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35
Joel Falcou wrote:
I'm stuck on some problem that may en dup silly.
<snip very beautifully written transform>
This works. If I remove the bp::when<bp::_, bm::size_t<0>()>, it fails to compile when I try to use a hand-overloaded operator<< for displaying expression values on standard output.
Could you post the code? The problem is probably pretty simple.
So, is there anything I missed (like deactivating operator<< in the grammar somehow ?) ?
Other question : When defining custom tag to build new function, why does the make_expr tempalte doesn't do check on its argument to see if it's match the grammar of the domain it's bound to use ? Seems I'm forced to add additional layer of SFINAE to prevent those function to get called on w/e types.
It's true, with make_expr you can create expressions that don't conform to the grammar for your domain. But a call to make_expr is pretty explicit -- it can't happen by accident. And make_expr is to be used by DSEL designers such as yourself who may use it to build an expression template piecemeal ... the intermediate pieces of which may not conform to the grammar, while the whole might. Does that make sense? -- Eric Niebler BoostPro Computing http://www.boostpro.com
Eric Niebler a écrit :
<snip very beautifully written transform>
I take this as a compliment :D
Could you post the code? The problem is probably pretty simple. The complete code ? Wow, it may end up rather large. I'll pack it in some archive of only the DSL related part and attach it to this mail. It won't be compilable though as it has large roots into a even larger project. It's true, with make_expr you can create expressions that don't conform to the grammar for your domain. But a call to make_expr is pretty explicit -- it can't happen by accident. And make_expr is to be used by DSEL designers such as yourself who may use it to build an expression template piecemeal ... the intermediate pieces of which may not conform to the grammar, while the whole might. Does that make sense? I see. So it's my responsibility to write correct make_expr code then to SFINAE them out if I need it. The current problem arise with a simple complex number DSL I'm writing as an introductory example for a master degree 'Generic Programming in C++' lesson I'm building up. I have a conj_ tag which represents taking the conjugate of a complex number.
The function itself is : template<class X> typename proto::result_of::make_expr<conj_, complex_domain,X const &>::type conj( X const& x ) { return proto::make_expr<conj_,complex_domain>(boost::cref(x)); } this works but if I write stupid code like : z = conj("lol"); I got a large message telling me char* const don't have w/e properties THEN a 'no such function conj(char* const)' If I add a small enable_if using matches over X, it works as I want it. So if I understand correctly, this is the intended behavior and I have to SFINAE stuff out. ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35
Well ofc I have to fail and forgot the zip v_v Here it is. It contains folder : dimen, which have all the context,expression,entity and grammar & ast which contains some helper I wrote -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35
Joel Falcou wrote:
Well ofc I have to fail and forgot the zip v_v Here it is. It contains folder : dimen, which have all the context,expression,entity and grammar & ast which contains some helper I wrote
This is a bug in Proto. The following small program reproduces the error: #include <iostream> #include <boost/proto/proto.hpp> namespace mpl = boost::mpl; namespace proto = boost::proto; using proto::_; template<class E> struct e; struct g : proto::or_< proto::terminal<int> , proto::plus<g,g> > {}; struct d : proto::domain<proto::generator<e>, g> {}; template<class E> struct e : proto::extends<E, e<E>, d> { BOOST_MPL_ASSERT((proto::matches<E, g>)); e(E const &x = E()) : proto::extends<E, e<E>, d>(x) {} }; e<proto::terminal<int>::type> i; template<class E> std::ostream &operator<<(std::ostream &sout, e<E> const &x) { return sout; } int main() { std::cout << (i+i); } The operator<< in the output expression can potentially match either the ostream inserter we've defined above or Proto's operator<<. Proto's operator overload *should* be disabled with SFINAE because the resulting expression type doesn't match the domain's grammar. But the failure happens before we get that far. Before checking the return type against the grammar, Proto first calculates the return type, which first involves Protofying std::cout, resulting in e<proto::terminal<std::ostream &>::type>. This is where the failure occurs because this simple terminal expression *also* doesn't match the grammar. That triggers the static assertion failure in e<>. In your case, you run into this problem because in dimen_expr<> you invoke the size_ metafunction, which invokes the dimen_size transform. If it is not critical that size_type and size_value be members of dimen_expr, you could work around the problem by making them external and calculating them only when you need them. That might improve compile times, too. Or go with the workaround you currently have. I'll see about fixing this bug. Please open a track ticket. Thanks. -- Eric Niebler BoostPro Computing http://www.boostpro.com
Eric Niebler a écrit :
This is a bug in Proto. The following small program reproduces the error: <snip> I'll see about fixing this bug. Please open a track ticket. Thanks. Ok , ticket is :
http://svn.boost.org/trac/boost/ticket/2407 Thanks for the head up :) I'll keep the work-around for now on and wait for a bug fix :) -- ___________________________________________ Joel Falcou - Assistant Professor PARALL Team - LRI - Universite Paris Sud XI Tel : (+33)1 69 15 66 35
Joel Falcou wrote:
Eric Niebler a écrit :
This is a bug in Proto. The following small program reproduces the error: <snip> I'll see about fixing this bug. Please open a track ticket. Thanks. Ok , ticket is :
http://svn.boost.org/trac/boost/ticket/2407
Thanks for the head up :) I'll keep the work-around for now on and wait for a bug fix :)
This bug is now fixed in trunk as of revision 49812. Sorry for the delay. https://svn.boost.org/trac/boost/changeset/49812 -- Eric Niebler BoostPro Computing http://www.boostpro.com
participants (2)
-
Eric Niebler
-
Joel Falcou