1

Hello I am trying to use spirit x3 to stuff strings to a vector, but I get the following error.The code is straight up from the documentation, except the vector uses strings.

error: no matching function for call to 
std::vector<std::__cxx11::basic_string<char> 
>::push_back(boost::spirit::x3::unused_type&)’
auto push_back = [&](auto& ctx){ slt.push_back(_attr(ctx)); };`

My code looks like this, I think all the necessary includes are on it(it's inside a class method):

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

#include <algorithm>
#include <bitset>
#include <fstream>
#include <iostream>
#include <iterator>
#include <map>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>

namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;

using x3::double_;
using x3::phrase_parse;
using x3::_attr;
using x3::parse;
using x3::lit;
using x3::char_;
using x3::lexeme;
using x3::alpha;
using x3::alnum;
using x3::skip;
using ascii::space;

/*Something,something.......*/

auto name = x3::rule<class name>{}
                = char_("a-zA-Z") >> *char_("a-z_A-Z0-9");

auto args_l = x3::rule<class l>{}
                = " " >> (name % skip(space)[","]);

auto comment = x3::rule<class comment>{}
                = "//" >> *char_;

auto iter_start = line.begin();
auto iter_end = line.end();

vector<string> slt;

auto push_back = [&](auto& ctx){ slt.push_back(_attr(ctx)); };


bool result = parse(
        iter_start,
        iter_end,
        name[push_back] >> -args_l >> *(char_(" "))
);

/Something,something......./

2 Answers2

1

Your rule definition does not expose an attribute.

Like @llonesmiz pointed out, fix that:

auto name = x3::rule<class name, std::string>{}
    = char_("a-zA-Z") >> *char_("a-z_A-Z0-9");

And see it Live On Wandbox (boost-1.67)

Note: Bugs

If you have Boost 1.65-1.66, you'll run into How to make a recursive rule in boost spirit x3 in VS2017, (Live On Wandbox which was fixed in Boost 1.67 (and earlier too, by the way, e.g. Live on Wandbox/Boost 1.64)

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

namespace x3 = boost::spirit::x3;

namespace P {
    using namespace x3;

    auto name = x3::rule<class name, std::string>{}
        = char_("a-zA-Z") >> *char_("a-z_A-Z0-9");

    auto args_l = x3::rule<class l>{}
        = " " >> (name % skip(space)[","]);

    auto comment = x3::rule<class comment>{}
        = "//" >> *char_;
}

#include <iostream>
#include <iomanip>

int main() {
    std::string const line = "a90_b";
    auto iter_start = line.begin();
    auto iter_end = line.end();

    std::vector<std::string> slt;

    auto push_back = [&](auto& ctx){ slt.push_back(x3::_attr(ctx)); };

    bool result = parse(
            iter_start,
            iter_end,
            P::name[push_back] >> -P::args_l >> *x3::char_(" ")
        );

    for (auto& tok: slt) {
        std::cout << std::quoted(tok) << "\n";
    }

    if (iter_start!=iter_end)
        std::cout << "Remaining unparsed: " << std::quoted(std::string(iter_start, iter_end)) << "\n";

    return result? 0 : 255;
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Welcome to stackoverflow. Please also review https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – sehe Jul 03 '18 at 21:00
1

After anwering the question as-is, I looked at your code.

BONUS

Considering the rest of your code, maybe this is what you're after:

Live On Wandbox

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

namespace x3 = boost::spirit::x3;

namespace P {
    using namespace x3;

    auto name = x3::rule<class name, std::string>{}
        = lexeme [char_("a-zA-Z") >> *char_("a-z_A-Z0-9")];

    auto comment = x3::rule<class comment>{}
        = "//" >> *(char_-eol) 
        | "/*" >> *(char_ - "*/") >> "*/";

    auto args_l = skip(space|comment) [name % ','];
}

#include <iostream>
#include <iomanip>

int main() {
    for (std::string const line : { 
            "a90_b",
            "a90_b,   /*comment ignored*/ b8, //more stuff\nz",
        })
    {
        std::cout << "Parsing " << std::quoted(line) << "\n";

        auto iter_start = line.begin();
        auto iter_end   = line.end();

        std::vector<std::string> slt;
        bool result = parse(iter_start, iter_end, P::args_l, slt);

        if (result) {
                for (auto& tok: slt) {
                    std::cout << " -> " << std::quoted(tok) << "\n";
                }
        } else {
            std::cout << "Parsed failed\n";
        }

        if (iter_start!=iter_end) {
            std::cout << "Remaining unparsed: " << std::quoted(std::string(iter_start, iter_end)) << "\n";
        }
    }
}

Prints

Parsing "a90_b"
 -> "a90_b"
Parsing "a90_b,   /*comment ignored*/ b8, //more stuff
z"
 -> "a90_b"
 -> "b8"
 -> "z"
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Just for the record the syntax is more like that `a00 a00,A_1`. So it's a the first word is separated by space(s) with the others – Stavros Avramidis Jul 03 '18 at 21:16
  • Yeap, that seems fine. Also didn't know I can pass the struct directly to the parse that's saves some trouble. So this `BOOST_FUSION_ADAPT_STRUCT(Data, id, args)` fills up the struct in order? – Stavros Avramidis Jul 03 '18 at 23:00
  • 1
    I also leave the previous answer as solution, because it provides more useful info for someone with a relative problem – Stavros Avramidis Jul 03 '18 at 23:01
  • I'd point here https://ciere.com/cppnow15/x3_docs/spirit/tutorials/employee___parsing_into_structs.html (most of the Qi docs also apply) – sehe Jul 03 '18 at 23:04
  • aha, I see a problem with that I think I can't use the micro for a private struct insde a class ..? – Stavros Avramidis Jul 03 '18 at 23:20
  • Please rephrase? I don't know what "the micro" is. Also, there is little difference between a struct and a class, essentially. – sehe Jul 03 '18 at 23:56
  • Sorry Macro (autocorrector), I meant I don't think I can do this: `class myClass{private:struct myStruct{}};` `BOOST_FUSION_ADAPT_STRUCT(myClass::myStruct,...)` – Stavros Avramidis Jul 04 '18 at 08:03