|
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:
and here is the compiler output:
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