[phoenix] Help needed with a custom terminal

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.

On Saturday 25 August 2012 15:28:25 you wrote:
Hi,
[snip]
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?
After some digging around, I think I found the source of the problem. Boost.Phoenix specializes is_nullary for custom_terminal<T> to be always true and I see no way around it on my side. The compiler either prefers this specialization over mine or produces an error of abiguous specializations of is_nullary. Can this be fixed? Or is there another way to do what I need?
participants (1)
-
Andrey Semashev