Opened 10 years ago

Closed 10 years ago

#7254 closed Bugs (fixed)

Proto expressions are not MPL sequences

Reported by: Mathias Gaunard Owned by: Eric Niebler
Milestone: To Be Determined Component: proto
Version: Boost Development Trunk Severity: Problem
Keywords: Cc:

Description

Proto expressions are not MPL sequences. It is arguably possible to get a MPL sequence by using boost::fusion::result_of::as_vector, but this may have undesirable overhead.

Change History (7)

comment:1 by Eric Niebler, 10 years ago

I've wanted to do this, but there's a snag. MPL sequences use tag dispatching. You can get the tag of an MPL sequence either by specializing mpl::sequence_tag or by having a nested tag typedef in your sequence type. Neither is satisfactory for Proto.

Specializing mpl::sequence_tag is a non-starter because any type that uses proto::extends or BOOST_PROTO_EXTENDS can be a Proto expression. This is an open set.

Having a nested tag type is a non-starter because expressions are part of end-users' APIs, and Proto shouldn't be claiming such a common identifier for itself. Someone might want e.tag to mean something in their DSL.

BTW, Fusion doesn't have this problem because it uses fusion_tag instead of simply tag.

I'm open to suggestions.

comment:2 by Mathias Gaunard, 10 years ago

I don't mind adding the tag in my expressions myself.

But typedef boost::fusion::fusion_sequence_tag tag; doesn't work.

It says there is no convert_impl for the proto expression tag.

comment:3 by Eric Niebler, 10 years ago

The following works just fine for me:

#include <iostream>
#include <typeinfo>
#include <boost/proto/proto.hpp>
#include <boost/fusion/mpl.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/placeholders.hpp>
#include <boost/type_traits/remove_reference.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
namespace fusion = boost::fusion;

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;
};

struct noop
{
    typedef void result_type;

    template<typename T>
    void operator()(T const &) const
    {
        std::cout << typeid(T).name() << std::endl;
    }
};

int main()
{
    my_expr<proto::terminal<int>::type> i;
    mpl::for_each<decltype(i + i), boost::remove_reference<mpl::_1> >(noop());
}

comment:4 by Mathias Gaunard, 10 years ago

Try calling mpl::pop_back on that type, I get the following error:

invalid use of incomplete type `struct boost::fusion::extension::convert_impl<boost::proto::tagns_::tag::proto_expr>'

comment:5 by Eric Niebler, 10 years ago

Interesting. Looks like an undocumented Fusion customization point. I can guess what it's supposed to do, but I'm following up on the boost list about it. At the very least, it's a bug in Fusion's docs. Let's wait and see what Joel says.

comment:6 by Eric Niebler, 10 years ago

Status: newassigned

Fixed on trunk in [80273].

comment:7 by Eric Niebler, 10 years ago

Resolution: fixed
Status: assignedclosed
Note: See TracTickets for help on using tickets.