
On 8/30/2012 12:59 AM, Eric Niebler wrote:
On 8/29/2012 12:58 AM, Joel de Guzman wrote:
On 8/28/2012 2:06 PM, Eric Niebler wrote:
IMO, this is less than ideal. In this case, it so happens that tag and domain are pure compile-time information, and can be bundled with the fusion tag. Generally, that won't be the case. Any type that models a more refined concept than Fusion[xxx]Sequence can have additional requirements that would be effectively sliced off by round-tripping through this customization point.
Joel, do you have thoughts about this? Would extensible Fusion sequences solve this?
In my mind, if we have forward and backward extensible Fusion sequences (and we should), the proper CP will be fusion::pop_back_impl. Fusion's mpl extensions, e.g. mpl::pop_back_impl will simply call fusion's CP for known (traits) forward and backward extensible Fusion sequences and default to the original behavior for non-extensible Fusion sequences (as before).
Makes sense.
Convert is another story. And as you pointed out, it looks like it needs more info than is provided in the CP. But still I lack proper understanding of this particular use-case. In general, convert should be able to convert any fusion sequence T (including MPL sequences) to another sequence U.
The problem was reported by Mathias Guarnard and reported here: <https://svn.boost.org/trac/boost/ticket/7254>
He was calling mpl::pop_back on a Proto expression and it was failing. Here is the code, which fails on 1.51 but will succeed on trunk because of my ugly hack:
#include <boost/proto/proto.hpp> #include <boost/fusion/mpl.hpp> #include <boost/mpl/pop_back.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/static_assert.hpp> namespace mpl = boost::mpl; namespace proto = boost::proto; namespace fusion = boost::fusion; using proto::_;
template<class E> struct my_expr;
struct my_domain : proto::domain<proto::generator<my_expr> > {};
template<class E> struct my_expr : proto::extends<E, my_expr<E>, my_domain> { my_expr(E const &e = E()) : proto::extends<E, my_expr<E>, my_domain>(e) {}
typedef fusion::fusion_sequence_tag tag; };
template<typename T> void test_impl(T const &) { typedef typename mpl::pop_back<T>::type result_type; BOOST_STATIC_ASSERT( (boost::is_same< result_type , my_expr<proto::basic_expr<proto::tag::plus, proto::list1<my_expr<proto::terminal<int>::type>&> > > >::value) ); }
// Test that we can call mpl algorithms on proto expression types, and get proto expression types back void test_mpl() { my_expr<proto::terminal<int>::type> i; test_impl(i + i); }
The MPL tag of the Proto expression is fusion_sequence_tag, so mpl::pop_back uses fusion's mpl hooks. The fusion implementation of mpl pop_pack first creates a fusion iterator_range of fusion pop_back iterators, both of which wrap a proto expression iterator. Then, fusion calls convert to turn this fusion sequence back into a proto expression before handing it back to mpl.
Proto, in the convert_impl CP, just sees a fusion range of proto expressions coming in. It can't know in general what proto expression was initially used before fusion modified it, so it can't find out what that expression's tag type was. And it needs to know that if it's to turn the sequence of child expressions back into an expression.
Does that help?
Yes. My gut feeling is that the "convert" mechanism is either 1) broken or 2) we are asking it to do more than it is designed for. I am not sure which. The intent of the convert mechanism is to be able to generate a container C from any type of sequence S. Now, in general we don't know the exact type of C. E.g. We know that it is a vector, but what particular type --the number of elements and element types we don't care about. All we know is that, hey, I have a sequence S and I want to create a vector. Fill in the blanks (elements and element types) for me. So that is why it is tag based. So, for example, if I want to convert S to a fusion vector, I do: result_of::convert<tag-of-vector, S>::type This is the generalized mechanism behind: result_of::as_vector<S>::type As mentioned, S can be any sequence type. It can be an MPL sequence, it can be a vector, a list, etc. So, there is no way really to provide more information about S other than the requirements for a forward fusion sequence. So, if a container C is not generally not convertible from any arbitrary sequence S, then, it probably does not satisfy the convertible (inventing the name for the sake of discussion) concept. Yes, it's not really a formalized concept, but all the built-in fusion sequences have this ability. Take a peek at the docs (e.g. http://tinyurl.com/6xlnxd8) and notice that containers can take in any sequence S in its constructor. E.g.: V(s) // Copy constructs a vector from a Forward Sequence, s. ------------------ I think I am going to embark on some fusion-care. It's really not that difficult to add the extensible sequence concepts and CPs. Apart from that, there are other pressing matters that I need to take care of anyway; rvalue handling comes to mind. Regards, -- Joel de Guzman http://www.boostpro.com http://boost-spirit.com