c++boost-spiritboost-fusionboost-spirit-karma

Spirit karma grammar issue when one rule uses BOOST_FUSION_ADAPT_STRUCT


I am trying to create a Spirit Karma grammar that is composed of several rules. This grammar is intended to create a string of the format "(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)". The rule to print out each individual struct that I call RowData uses BOOST_FUSION_ADAPT_STRUCT to print out all of the fields of that struct. If the grammar only includes that rule, the grammar works fine. However, I am using this struct as the value of a std::map. The key in an integer but I do not care about that value and want to drop it. I have created rules to parse the std::map but the rule that handles the std::pair fails to compile for a BOOST_SPIRIT_ASSERT_MATCH. I have created a small bit of code that generates this issue. The line is pairRule = bs::karma::omit << rowDataRule; If anybody has an idea what the issue is or how I could do this differently, I would appreciate the help.

Edit: I am using gcc 4.8.3 on OpenSUSE 13.2 but get the same error with gcc 4.8.2 on Ubuntu 14.04 LTS.

main.cpp

#include <iostream>
#include <map>

#include <boost/cstdint.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/make_tuple.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/spirit/include/karma.hpp>

namespace bs = boost::spirit;

struct RowData
{
    RowData() :
        field0(0),
        field1(0),
        field2(0),
        field3(0)
    {
    }

    boost::uint64_t field0;
    boost::uint64_t field1;
    boost::uint64_t field2;
    boost::uint64_t field3;
};

BOOST_FUSION_ADAPT_STRUCT(
    RowData,
    (boost::uint64_t, field0)
    (boost::uint64_t, field1)
    (boost::uint64_t, field2)
    (boost::uint64_t, field3)
)

template <typename OutputIterator>
struct RowDataGrammar :
    bs::karma::grammar< OutputIterator, std::map<boost::uint64_t, RowData>() >
{
    RowDataGrammar() : RowDataGrammar::base_type(allRowsRule)
    {
        rowDataRule =
            bs::karma::lit("(") <<
            bs::karma::ulong_ <<
            bs::karma::lit(", ") <<
            bs::karma::ulong_ <<
            bs::karma::lit(", ") <<
            bs::karma::ulong_ <<
            bs::karma::lit(", ") <<
            bs::karma::ulong_ <<
            bs::karma::lit(")");

        // I only want the value from the map. The key is dropped.
        pairRule = bs::karma::omit << rowDataRule;

        allRowsRule = pairRule % ", ";
    }

private:
    bs::karma::rule< OutputIterator, RowData() > rowDataRule;
    bs::karma::rule< OutputIterator, std::pair<boost::uint64_t, RowData>() > pairRule;
    bs::karma::rule< OutputIterator, std::map<boost::uint64_t, RowData>() >  allRowsRule;
};

int main(int argc, char** argv)
{
    std::map<boost::uint64_t, RowData> rowMap;

    RowData rowData;
    rowData.field0 = 0;
    rowData.field1 = 1;
    rowData.field2 = 2;
    rowData.field3 = 3;
    rowMap.insert(std::make_pair(10, rowData));

    rowData.field0 = 6;
    rowData.field1 = 7;
    rowData.field2 = 8;
    rowData.field3 = 9;
    rowMap.insert(std::make_pair(20, rowData));

    std::string generatedString;
    std::back_insert_iterator<std::string> sink(generatedString);
    RowDataGrammar< std::back_insert_iterator<std::string> > grammar;

    bs::karma::generate(sink, grammar, rowMap);

    std::cout << "output :" << generatedString << std::endl;
}

Error message:

In file included from /usr/include/boost/fusion/support/tag_of.hpp:16:0,
                 from /usr/include/boost/fusion/support/category_of.hpp:11,
                 from /usr/include/boost/fusion/adapted/struct/detail/extension.hpp:13,
                 from /usr/include/boost/fusion/adapted/struct/adapt_struct.hpp:19,
                 from karmaTest.cpp:5:
/usr/include/boost/spirit/home/karma/nonterminal/rule.hpp: In instantiation of ‘static void boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>::define(boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>&, const Expr&, mpl_::false_) [with Auto = mpl_::bool_<false>; Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>; OutputIterator = std::back_insert_iterator<std::basic_string<char> >; T1 = std::pair<long unsigned int, RowData>(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type; mpl_::false_ = mpl_::bool_<false>]’:
/usr/include/boost/spirit/home/karma/nonterminal/rule.hpp:229:19:   required from ‘boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>& boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>::operator=(const Expr&) [with Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>; OutputIterator = std::back_insert_iterator<std::basic_string<char> >; T1 = std::pair<long unsigned int, RowData>(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’
karmaTest.cpp:54:18:   required from ‘RowDataGrammar<OutputIterator>::RowDataGrammar() [with OutputIterator = std::back_insert_iterator<std::basic_string<char> >]’
karmaTest.cpp:84:62:   required from here
/usr/include/boost/spirit/home/karma/nonterminal/rule.hpp:185:13: error: no matching function for call to ‘assertion_failed(mpl_::failed************ (boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>::define(boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>&, const Expr&, mpl_::false_) [with Auto = mpl_::bool_<false>; Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>; OutputIterator = std::back_insert_iterator<std::basic_string<char> >; T1 = std::pair<long unsigned int, RowData>(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type; mpl_::false_ = mpl_::bool_<false>]::error_invalid_expression::************)(boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>))’
             BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr);
             ^
/usr/include/boost/spirit/home/karma/nonterminal/rule.hpp:185:13: note: candidate is:
/usr/include/boost/mpl/assert.hpp:82:5: note: template<bool C> int mpl_::assertion_failed(typename mpl_::assert<C>::type)
 int assertion_failed( typename assert<C>::type );
     ^
/usr/include/boost/mpl/assert.hpp:82:5: note:   template argument deduction/substitution failed:
/usr/include/boost/spirit/home/karma/nonterminal/rule.hpp:185:13: note:   cannot convert ‘boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>::define(boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>&, const Expr&, mpl_::false_)::error_invalid_expression185::assert_arg<mpl_::bool_<false>, boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l> >()’ (type ‘mpl_::failed************ (boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>::define(boost::spirit::karma::rule<OutputIterator, T1, T2, T3, T4>&, const Expr&, mpl_::false_) [with Auto = mpl_::bool_<false>; Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>; OutputIterator = std::back_insert_iterator<std::basic_string<char> >; T1 = std::pair<long unsigned int, RowData>(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type; mpl_::false_ = mpl_::bool_<false>]::error_invalid_expression::************)(boost::proto::exprns_::expr<boost::proto::tagns_::tag::shift_left, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::omit>, 0l>&, boost::spirit::karma::rule<std::back_insert_iterator<std::basic_string<char> >, RowData(), boost::spirit::unused_type, boost::spirit::unused_type, boost::spirit::unused_type>&>, 2l>)’) to type ‘mpl_::assert<false>::type {aka mpl_::assert<false>}’
             BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr);

Solution

  • As cv_and_he said, I was using omit incorrectly. An old coworker I reached out to told me the same. The corrected code is below.

    main.cpp

    #include <iostream>
    #include <map>
    
    #include <boost/cstdint.hpp>
    #include <boost/fusion/adapted/struct/adapt_struct.hpp>
    #include <boost/fusion/include/adapt_struct.hpp>
    #include <boost/fusion/include/make_tuple.hpp>
    #include <boost/fusion/include/std_pair.hpp>
    #include <boost/spirit/include/karma.hpp>
    
    namespace bs = boost::spirit;
    
    struct RowData
    {
        RowData() :
            field0(0),
            field1(0),
            field2(0),
            field3(0)
        {
        }
    
        boost::uint64_t field0;
        boost::uint64_t field1;
        boost::uint64_t field2;
        boost::uint64_t field3;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(
        RowData,
        (boost::uint64_t, field0)
        (boost::uint64_t, field1)
        (boost::uint64_t, field2)
        (boost::uint64_t, field3)
    )
    
    template <typename OutputIterator>
    struct RowDataGrammar :
        bs::karma::grammar< OutputIterator, std::map<boost::uint64_t, RowData>() >
    {
        RowDataGrammar() : RowDataGrammar::base_type(allRowsRule)
        {
            rowDataRule =
                bs::karma::lit("(") <<
                bs::karma::ulong_ <<
                bs::karma::lit(", ") <<
                bs::karma::ulong_ <<
                bs::karma::lit(", ") <<
                bs::karma::ulong_ <<
                bs::karma::lit(", ") <<
                bs::karma::ulong_ <<
                bs::karma::lit(")");
    
            // I only want the value from the map. The key is dropped.
            pairRule = bs::karma::omit[bs::karma::ulong_] << rowDataRule;
    
            allRowsRule = pairRule % ", ";
        }
    
    private:
        bs::karma::rule< OutputIterator, RowData() > rowDataRule;
        bs::karma::rule< OutputIterator, std::pair<boost::uint64_t, RowData>() > pairRule;
        bs::karma::rule< OutputIterator, std::map<boost::uint64_t, RowData>() >  allRowsRule;
    };
    
    int main(int argc, char** argv)
    {
        std::map<boost::uint64_t, RowData> rowMap;
    
        RowData rowData;
        rowData.field0 = 0;
        rowData.field1 = 1;
        rowData.field2 = 2;
        rowData.field3 = 3;
        rowMap.insert(std::make_pair(10, rowData));
    
        rowData.field0 = 6;
        rowData.field1 = 7;
        rowData.field2 = 8;
        rowData.field3 = 9;
        rowMap.insert(std::make_pair(20, rowData));
    
        std::string generatedString;
        std::back_insert_iterator<std::string> sink(generatedString);
        RowDataGrammar< std::back_insert_iterator<std::string> > grammar;
    
        bs::karma::generate(sink, grammar, rowMap);
    
        std::cout << "output :" << generatedString << std::endl;
    }