Search code examples
c++boostboost-spiritboost-spirit-x3

Can't compile a boost::spirit::x3 parser with lambda parameters


Based on an answer here, I wrote the following parser:

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>

#include <fstream>
#include <iostream>
#include <vector>

namespace x3 = boost::spirit::x3;

int main() {

    std::ifstream input("input.txt");
    boost::spirit::istream_iterator begin(input >> std::noskipws), end;

    std::vector<float> data1, data2;
    auto capture1 = [&](auto& ctx){ data1.emplace_back(_attr(ctx)); };
    auto capture2 = [&](auto& ctx){ data2.emplace_back(_attr(ctx)); };

    auto sequence1 =  "v" >> x3::float_[capture1] >> x3::float_[capture1] >> x3::float_[capture1];
    auto sequence2 =  "vn" >> x3::float_[capture2] >> x3::float_[capture2] >> x3::float_[capture2];

    auto skipper = x3::blank | '#' >> *(x3::char_ - x3::eol) >> (x3::eol|x3::eoi);
    auto rule = x3::skip(skipper) [ *x3::eol >> 
        *( +(sequence1 >> (x3::eoi|+x3::eol) ) >>
           *(sequence2 >> (x3::eoi|+x3::eol) ) )
    ];

    if (x3::parse(begin, end, rule)) {

        std::cout << "data1 size: " << data1.size() << "\n";

        for(float& i:data1)
            std::cout << i << ", ";
        std::cout << '\n';

        std::cout << "data2 size: " << data2.size() << "\n";
        for(float& i:data2)
            std::cout << i << ", ";
        std::cout << '\n';

    } else 
        std::cout << "failed to parse!\n";
    
    if(begin!=end)
        std::cerr<< "did not parsed completely!";


    //---------------------------------
    std::cout << "\ndone!\n";
    return EXIT_SUCCESS;
}

And my input file looks something like this:


# group 1

v -111.11 -0.017928 0.005579
v -0.014504 -0.017928 0.010577
v -0.010538 -0.017928 0.014543
v -0.005540 -0.017928 0.017090

vn -111.11 -0.017928 0.005579
vn -0.014504 -0.017928 0.010577
vn -0.010538 -0.017928 0.014543


# group 2

v 0.005540 -0.017928 0.017090
v 0.010538 -0.017928 0.014543
v 0.014504 -0.017928 0.010577

vn 0.014504 -0.017928 0.010577
vn 0.017050 -0.017928 0.005579
vn 0.017928 -0.017928 0.000039
vn -0.010538 -0.017928 0.014543


# group 3  
# and so on..

The same code was compiled and parsed correctly with the following settings:

  • on windows 10 with boost-1.67.0 and gcc by MinGW-W64 7.3.0 "compiled and parsed fine!"
  • on debian 9 with boost-1.62.0 and gcc 6.3.0 "compiled and parsed fine!"

However I was not able to compile it on ubuntu 18.04 with boost-1.65.1 and gcc (7.5.0 , 9.3.0, and 10.1.0) with (c++14, c++17 or c++20).

Here is a part of error msg:

In file included from /usr/include/boost/spirit/home/x3/directive/expect.hpp:12,
                 from /usr/include/boost/spirit/home/x3/auxiliary/guard.hpp:11,
                 from /usr/include/boost/spirit/home/x3/auxiliary.hpp:13,
                 from /usr/include/boost/spirit/home/x3.hpp:14,
                 from parser.cpp:1:
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp: In instantiation of 'static bool boost::spirit::x3::detail::parse_into_container_impl<Parser, Context, RContext, typename boost::enable_if<boost::spirit::x3::traits::handles_container<Parser, Context> >::type>::call(const Parser&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&, mpl_::true_) [with Iterator = boost::spirit::basic_istream_iterator<char>; Attribute = const boost::spirit::x3::unused_type; Parser = boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; mpl_::true_ = mpl_::bool_<true>]':
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:281:24:   required from 'static bool boost::spirit::x3::detail::parse_into_container_impl<Parser, Context, RContext, typename boost::enable_if<boost::spirit::x3::traits::handles_container<Parser, Context> >::type>::call(const Parser&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&) [with Iterator = boost::spirit::basic_istream_iterator<char>; Attribute = const boost::spirit::x3::unused_type; Parser = boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type]'
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:293:74:   required from 'bool boost::spirit::x3::detail::parse_into_container(const Parser&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&) [with Parser = boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >; Iterator = boost::spirit::basic_istream_iterator<char>; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; Attribute = const boost::spirit::x3::unused_type]'
/usr/include/boost/spirit/home/x3/operator/detail/sequence.hpp:378:33:   required from 'bool boost::spirit::x3::detail::parse_sequence(const Parser&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&, boost::spirit::x3::traits::container_attribute) [with Parser = boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > >; Iterator = boost::spirit::basic_istream_iterator<char>; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; Attribute = const boost::spirit::x3::unused_type]'
/usr/include/boost/spirit/home/x3/operator/detail/sequence.hpp:463:32:   required from 'static bool boost::spirit::x3::detail::parse_into_container_impl<boost::spirit::x3::sequence<L, R>, Context, RContext>::call(const parser_type&, Iterator&, const Iterator&, const Context&, RContext&, Attribute&, mpl_::false_) [with Iterator = boost::spirit::basic_istream_iterator<char>; Attribute = const boost::spirit::x3::unused_type; Left = boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >; Right = boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; boost::spirit::x3::detail::parse_into_container_impl<boost::spirit::x3::sequence<L, R>, Context, RContext>::parser_type = boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > >; mpl_::false_ = mpl_::bool_<false>]'
/usr/include/boost/spirit/home/x3/operator/detail/sequence.hpp:496:24:   [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/spirit/home/x3/operator/kleene.hpp:32:48:   required from 'bool boost::spirit::x3::kleene<Subject>::parse(Iterator&, const Iterator&, const Context&, RContext&, Attribute&) const [with Iterator = boost::spirit::basic_istream_iterator<char>; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; Attribute = const boost::spirit::x3::unused_type; Subject = boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > >]'
/usr/include/boost/spirit/home/x3/operator/sequence.hpp:32:37:   required from 'bool boost::spirit::x3::sequence<Left, Right>::parse(Iterator&, const Iterator&, const Context&, RContext&, boost::spirit::x3::unused_type) const [with Iterator = boost::spirit::basic_istream_iterator<char>; Context = boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >, boost::spirit::x3::unused_type>; RContext = const boost::spirit::x3::unused_type; Left = boost::spirit::x3::kleene<boost::spirit::x3::eol_parser>; Right = boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > > >]'
/usr/include/boost/spirit/home/x3/directive/skip.hpp:75:39:   required from 'bool boost::spirit::x3::skip_directive<Subject, Skipper>::parse(Iterator&, const Iterator&, const Context&, RContext&, Attribute&) const [with Iterator = boost::spirit::basic_istream_iterator<char>; Context = boost::spirit::x3::unused_type; RContext = const boost::spirit::x3::unused_type; Attribute = const boost::spirit::x3::unused_type; Subject = boost::spirit::x3::sequence<boost::spirit::x3::kleene<boost::spirit::x3::eol_parser>, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > > > >; Skipper = boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > >]'
/usr/include/boost/spirit/home/x3/core/parse.hpp:35:34:   required from 'bool boost::spirit::x3::parse_main(Iterator&, Iterator, const Parser&, Attribute&) [with Iterator = boost::spirit::basic_istream_iterator<char>; Parser = boost::spirit::x3::skip_directive<boost::spirit::x3::sequence<boost::spirit::x3::kleene<boost::spirit::x3::eol_parser>, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > > > >, boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > > >; Attribute = const boost::spirit::x3::unused_type]'
/usr/include/boost/spirit/home/x3/core/parse.hpp:71:26:   required from 'bool boost::spirit::x3::parse(Iterator&, Iterator, const Parser&) [with Iterator = boost::spirit::basic_istream_iterator<char>; Parser = boost::spirit::x3::skip_directive<boost::spirit::x3::sequence<boost::spirit::x3::kleene<boost::spirit::x3::eol_parser>, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::plus<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > >, boost::spirit::x3::kleene<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_string<const char*, boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::action<boost::spirit::x3::real_parser<float>, main()::<lambda(auto:2&)> > >, boost::spirit::x3::alternative<boost::spirit::x3::eoi_parser, boost::spirit::x3::plus<boost::spirit::x3::eol_parser> > > > > > >, boost::spirit::x3::alternative<boost::spirit::x3::char_class<boost::spirit::char_encoding::standard, boost::spirit::x3::blank_tag>, boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::kleene<boost::spirit::x3::difference<boost::spirit::x3::any_char<boost::spirit::char_encoding::standard>, boost::spirit::x3::eol_parser> > >, boost::spirit::x3::alternative<boost::spirit::x3::eol_parser, boost::spirit::x3::eoi_parser> > > >]'
parser.cpp:28:35:   required from here
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:254:22: error: 'const struct boost::spirit::x3::unused_type' has no member named 'empty'
  254 |             if (attr.empty())
      |                 ~~~~~^~~~~
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:259:22: error: 'const struct boost::spirit::x3::unused_type' has no member named 'insert'
  259 |                 attr.insert(attr.end(), rest.begin(), rest.end());
      |                 ~~~~~^~~~~~
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:259:34: error: 'const struct boost::spirit::x3::unused_type' has no member named 'end'
  259 |                 attr.insert(attr.end(), rest.begin(), rest.end());
      |                             ~~~~~^~~
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:259:46: error: 'const struct boost::spirit::x3::unused_type' has no member named 'begin'
  259 |                 attr.insert(attr.end(), rest.begin(), rest.end());
      |                                         ~~~~~^~~~~
/usr/include/boost/spirit/home/x3/core/detail/parse_into_container.hpp:259:60: error: 'const struct boost::spirit::x3::unused_type' has no member named 'end'
  259 |                 attr.insert(attr.end(), rest.begin(), rest.end());
      |

.
.
.
.

I also tried a suggestion as in this answer, but it still won't compile!

Can someone point out where I'm doing it wrong, or at least what MIGHT BE causing this? Thanks


Solution

  • It's a known and fixed bug in 1.65.0, 1.65.1 and 1.66

    See it for yourself: https://wandbox.org/permlink/32WK3LoPb8yqmfsV (switch boost versions on the left).

    Workaround?

    Here's a simplified version - the parser is unchanged but more readable (that's me reviewing the code) and the input is hard-coded for Compiler Explorer:

    #include <boost/spirit/home/x3.hpp>
    #include <boost/spirit/include/support_istream_iterator.hpp>
    
    #include <fstream>
    #include <fmt/ranges.h>
    
    namespace x3 = boost::spirit::x3;
    
    int main() {
        std::string const& input = R"(# group 1
    v -111.11 -0.017928 0.005579
    vn -111.11 -0.017928 0.005579
    # group 2
    v 0.005540 -0.017928 0.017090
    vn 0.014504 -0.017928 0.010577
    # and so on..)";
    
        auto triplet = [](auto id, auto& v) {
            auto action = [&v](auto& ctx){ v.emplace_back(x3::_attr(ctx)); };
            return id >> x3::repeat(3) [x3::double_ [action]];
        };
    
        auto NL = x3::eoi|+x3::eol;
        auto skipper = x3::blank | '#' >> *(x3::char_ - x3::eol) >> NL;
    
        std::vector<float> v, vn;
        auto rule = x3::skip(skipper) [ -NL >> 
            *( +(triplet("v",  v)  >> NL) >>
            *(triplet("vn", vn) >> NL) )
        ];
    
        if (x3::parse(begin(input), end(input), rule >> x3::eoi)) {
            fmt::print("v: {}\nvn: {}\n", v, vn);
        }
    }
    

    Prints

    v: {-111.11, -0.017928, 0.005579, 0.00554, -0.017928, 0.01709}
    vn: {-111.11, -0.017928, 0.005579, 0.014504, -0.017928, 0.010577}
    

    Note how this, due the semantic actions, conflates data sequences from different groups. Compare to below!

    Now switching to 1.66.0 also fails: https://godbolt.org/z/bjvETE

    However, here's even further simplified but without any semantic actions:

    Live On Compiler Explorer

    #include <boost/fusion/adapted/std_tuple.hpp>
    #include <boost/spirit/home/x3.hpp>
    #include <boost/spirit/include/support_istream_iterator.hpp>
    
    #include <fstream>
    #include <fmt/ranges.h>
    
    namespace x3 = boost::spirit::x3;
    
    int main() {
        std::string const& input = R"(# group 1
    v -111.11 -0.017928 0.005579
    vn -111.11 -0.017928 0.005579
    # group 2
    v 0.005540 -0.017928 0.017090
    vn 0.014504 -0.017928 0.010577
    # and so on..)";
    
        auto NL = x3::eoi|+x3::eol;
        auto skipper = x3::blank | '#' >> *(x3::char_ - x3::eol) >> NL;
        auto triplet = x3::repeat(3) [x3::double_];
    
        using V = std::vector<float>;
        using VN = std::vector<float>;
        using Group = std::tuple<V, VN>;
    
        auto group
            = x3::rule<struct rule_id, Group> {"group"}
            = +("v" >> triplet >> NL) >>
            *("vn" >> triplet >> NL)
            ;
    
        auto rule = x3::skip(skipper) [ -NL >> *group ];
    
        std::vector<Group> groups;
        if (x3::parse(begin(input), end(input), rule >> x3::eoi, groups)) {
            fmt::print("{}\n", fmt::join(groups, "\n"));
        }
    }
    

    Most importantly, it no longer conflates groups:

    ({-111.11, -0.017928, 0.005579}, {-111.11, -0.017928, 0.005579})
    ({0.00554, -0.017928, 0.01709}, {0.014504, -0.017928, 0.010577})
    

    Printing the data without libfmt (Live On Coliru)

    for (auto& [v,vn] : groups) {
        std::cout << "\nv"; for  (auto&& f : v)  std::cout << " " << f;
        std::cout << "\nvn"; for (auto&& f : vn) std::cout << " " << f;
    }
    

    Output:

    v -111.11 -0.017928 0.005579
    vn -111.11 -0.017928 0.005579
    v 0.00554 -0.017928 0.01709
    vn 0.014504 -0.017928 0.010577
    

    TL;DR

    Just upgrade your boost version. Spirit is entirely header-only, so you might just be able to drop in 1.67.0 headers from boost/spirit/x3 into a project folder if you need.

    Off-topic: Semantic actions have drawbacks: Boost Spirit: "Semantic actions are evil"?.