$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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:
and here is the compiler output:
I'm using release SVN branch and GCC 4.6. Thanks in advance.