Boost logo

Boost :

Subject: [boost] [phoenix] Help needed with a custom terminal
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2012-08-25 07:28:25


Hi,

I'm trying to define a custom terminal that acts as a replacement of
operator<< in expressions when the right argument of the operator is of my
special type. The terminal aggregates its left subexpression which results in
reference to a stream, and result type of the terminal is the same reference.
In short, it looks like this:

  namespace my {

  struct argument
  {
    std::string m_value;

    explicit argument(std::string const& value);
  };

  template< typename LeftT >
  class output_terminal
  {
  public:
    typedef void _is_my_terminal;

    //! Self type
    typedef output_terminal this_type;

    //! Result type definition
    template< typename >
    struct result;

    template< typename ContextT >
    struct result< this_type(ContextT) >
    {
      typedef typename remove_cv<
        typename remove_reference< ContextT >::type
>::type context_type;
      typedef typename phoenix::evaluator::impl<
        typename LeftT::proto_base_expr&,
        context_type,
        phoenix::unused
>::result_type type;
    };

    template< typename ContextT >
    struct result< const this_type(ContextT) >
    {
      typedef typename remove_cv<
        typename remove_reference< ContextT >::type
>::type context_type;
      typedef typename phoenix::evaluator::impl<
        typename LeftT::proto_base_expr const&,
        context_type,
        phoenix::unused
>::result_type type;
    };

  private:
    //! Left argument actor
    LeftT m_left;
    //! Right argument
    std::string m_right;

  public:
    //! Initializing constructor
    output_terminal(LeftT const& left, std::string const& right);

    //! Invokation operator
    template< typename ContextT >
    typename result< const this_type(ContextT) >::type
    operator() (ContextT const& ctx) const
    {
      typedef typename result<
        const this_type(ContextT)
>::type result_type;
      result_type strm = phoenix::eval(m_left, ctx);
      strm << m_right;
      return strm;
    }
  };

  template< typename LeftExprT >
  inline phoenix::actor< output_terminal< phoenix::actor< LeftExprT > > >
  operator<< (phoenix::actor< LeftExprT > const& left, argument const& right)
  {
    phoenix::actor<
     output_terminal< phoenix::actor< LeftExprT > >
> res =
    {
      output_terminal< phoenix::actor< LeftExprT > >(left, right.m_value)
    };
    return res;
  }

  typedef phoenix::expression::argument< 1 >::type stream_type;
  const stream_type stream = {};

  } // namespace my

  int main(int, char*[])
  {
    function< void (std::ostream&) > func;
    func = my::operator<< (my::stream, my::argument("Hello, world!"));
    func(std::cout);

    return 0;
  }

I also have specialized phoenix::result_of::is_nullary,
phoenix::is_custom_terminal and phoenix::custom_terminal based on the
_is_my_terminal tag.

The problem is that the code doesn't compile. The compiler output is quite
lengthy and it ends in this:

./boost/fusion/adapted/struct/detail/at_impl.hpp:24:16: error: invalid use of
incomplete type ‘struct
boost::fusion::extension::access::struct_member<boost::phoenix::vector1<const
boost::phoenix::actor<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<my::output_terminal<boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0l> > > >, 0l> >*>,
1>’

It is not clear where the problem is but I think for some reason Boost.Phoenix
thinks that output_terminal is a nullary terminal, despite the fact that I
specialized is_nullary to return false. Is there something wrong with my code
or is it a problem with Boost.Phoenix?

I have posted the complete code here:

http://pastebin.com/Vniq1b5Y

and here is the compiler output:

http://pastebin.com/8Beg4LiY

I'm using release SVN branch and GCC 4.6. Thanks in advance.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk