c++boostboost-spiritboost-phoenix

boost::spirit attribute assignment: struct is_nullary: base type fails to be a struct or class type


I have a boost::spirit parser that is supposed to simply assign a pointer to its attribute:

rule<CompoundExpression *(Scope &)> var_ref = var<CompoundExpression>()(_r1) [
    _val = new_<Reference<Variable<CompoundExpression>>>(_1)
];

where var<CompoundExpression>() is a just function that returns a reference to a static rule that does the actual parsing. I use the same assignment action with other instantiations of the Reference<Variable<T>> template all over the code and it's fine, except for the one that uses the CompoundExpression parameter.

The literal GCC error is this:

In file included from /usr/include/boost/phoenix/core/actor.hpp:20,
                 from /usr/include/boost/phoenix/core.hpp:12,
                 from /usr/include/boost/spirit/include/phoenix_core.hpp:11,
                 from /usr/include/boost/spirit/home/support/argument.hpp:18,
                 from /usr/include/boost/spirit/home/qi/nonterminal/rule.hpp:29,
                 from /usr/include/boost/spirit/home/qi/nonterminal.hpp:14,
                 from /usr/include/boost/spirit/include/qi_nonterminal.hpp:16,
                 from /home/ich/sync/ConTrAkt/gologpp/src/parser/utilities.h:7,
                 from /home/ich/sync/ConTrAkt/gologpp/src/parser/compound_expression.h:4,
                 from /home/ich/sync/ConTrAkt/gologpp/src/parser/compound_expression.cpp:1:
/usr/include/boost/phoenix/core/is_nullary.hpp: In instantiation of ‘struct boost::phoenix::result_of::is_nullary<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::attribute<0> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::new_, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::detail::target<gologpp::Reference<gologpp::Variable<gologpp::TypedExpression<gologpp::CompoundType> > > > >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2>, void>’:
/usr/include/boost/phoenix/core/actor.hpp:178:13:   required from ‘struct boost::phoenix::result_of::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::attribute<0> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::new_, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::detail::target<gologpp::Reference<gologpp::Variable<gologpp::TypedExpression<gologpp::CompoundType> > > > >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2> >’
/usr/include/boost/phoenix/core/actor.hpp:271:9:   required from ‘struct boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::attribute<0> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::new_, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::detail::target<gologpp::Reference<gologpp::Variable<gologpp::TypedExpression<gologpp::CompoundType> > > > >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2> >’
/home/ich/sync/ConTrAkt/gologpp/src/parser/compound_expression.cpp:22:58:   required from here
/usr/include/boost/phoenix/core/is_nullary.hpp:115:16: error: base type ‘boost::phoenix::evaluator::impl<const boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::attribute<0> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::new_, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::detail::target<gologpp::Reference<gologpp::Variable<gologpp::TypedExpression<gologpp::CompoundType> > > > >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2>&, boost::phoenix::vector2<mpl_::bool_<true>, boost::phoenix::is_nullary>, boost::proto::envns_::empty_env>::result_type’ {aka ‘const boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::attribute<0> >, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::tag::new_, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::detail::target<gologpp::Reference<gologpp::Variable<gologpp::TypedExpression<gologpp::CompoundType> > > > >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2>&’} fails to be a struct or class type
         struct is_nullary
                ^~~~~~~~~~

Since that is virtually unreadable, I'll try to clang-format it. So I guess it comes down to the last line:

/usr/include/boost/phoenix/core/is_nullary.hpp:115:16: error: base type
‘boost::phoenix::evaluator::impl<
    const boost::proto::exprns_::basic_expr<
        boost::proto::tagns_::tag::assign,
        boost::proto::argsns_::list2<
            boost::proto::exprns_::expr<
                boost::proto::tagns_::tag::terminal,
                boost::proto::argsns_::term<boost::spirit::attribute<0>>, 0>,
            boost::phoenix::actor<boost::proto::exprns_::basic_expr<
                boost::phoenix::tag::new_,
                boost::proto::argsns_::list2<
                    boost::proto::exprns_::basic_expr<
                        boost::proto::tagns_::tag::terminal,
                        boost::proto::argsns_::term<
                            boost::phoenix::detail::target<gologpp::Reference<
                                gologpp::Variable<gologpp::TypedExpression<
                                    gologpp::CompoundType>>>>>,
                        0>,
                    boost::phoenix::actor<boost::spirit::argument<0>>>,
                2>>>,
        2> &,
    boost::phoenix::vector2<mpl_::bool_<true>, boost::phoenix::is_nullary>,
    boost::proto::envns_::empty_env>::result_type’ {
    aka ‘const boost::proto::exprns_::basic_expr<
        boost::proto::tagns_::tag::assign,
        boost::proto::argsns_::list2<
            boost::proto::exprns_::expr<
                boost::proto::tagns_::tag::terminal,
                boost::proto::argsns_::term<boost::spirit::attribute<0>>, 0>,
            boost::phoenix::actor<boost::proto::exprns_::basic_expr<
                boost::phoenix::tag::new_,
                boost::proto::argsns_::list2<
                    boost::proto::exprns_::basic_expr<
                        boost::proto::tagns_::tag::terminal,
                        boost::proto::argsns_::term<
                            boost::phoenix::detail::target<gologpp::Reference<
                                gologpp::Variable<gologpp::TypedExpression<
                                    gologpp::CompoundType>>>>>,
                        0>,
                    boost::phoenix::actor<boost::spirit::argument<0>>>,
                2>>>,
        2> &’}
fails to be a struct or class type

Note that gologpp::TypedExpression<gologpp::CompoundType is typedef'd as gologpp::CompoundExpression

Now if I'm reading that correctly, this base type of result_of::is_nullary (/usr/include/boost/phoenix/core/is_nullary.hpp:115) somehow happens to be a reference type and that is the problem. My Reference<Variable<CompoundExpression>> type seems perfectly fine, I can construct objects from it and otherwise use it as I'd expect. Also the problem it seems is with the whole phoenix assignment expression, and not with its LHS or RHS.

Looking at boost/phoenix/core/is_nullary.hpp:115:

        struct is_nullary
            : boost::phoenix::evaluator::impl<
                Expr const &
              , vector2<
                    mpl::true_
                  , boost::phoenix::is_nullary
                >
              , proto::empty_env
            >::result_type
        {};

It seems to that somehow Expr const & (which in my case is the assignment expression) is becoming the result_type, which shouldn't happen. But then why does it and how could I be causing it?


Solution

  • OK, so it looks like I also need to

    #include <boost/phoenix/object/dynamic_cast.hpp>
    #include <boost/phoenix/operator/self.hpp>
    

    for the polymorphic assignment to work. Something I didn't notice because it was indirectly included in other cases.