I am trying (and failing) to parse a map<int, variant<string, float>>
using Boost Spirit X3, with the following code:
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <map>
#include <variant>
#include <string>
using namespace std;
namespace x3 = boost::spirit::x3;
int main() {
auto variantRule = x3::rule<class VariantClass, x3::variant<std::string, float>>() = (*x3::alnum | x3::float_);
auto pairRule = x3::rule<class PairClass, pair<int, x3::variant<std::string, float>>>() = x3::int_ >> ":" >> variantRule;
auto mapRule = x3::rule<class MapClass, map<int, x3::variant<std::string, float>>>() = pairRule >> * ( "," >> pairRule );
string input = "1 : 1.0, 2 : hello, 3 : world";
map<int, x3::variant<std::string, float>> variantMap;
auto success = x3::phrase_parse(input.begin(), input.end(), mapRule, x3::space, variantMap);
return 0;
}
For some reason I can't parse maps of pair<int, variant<string, float>>
. I was able to parse a vector of variants though, it's only when I try to parse maps of variants that my code fails. It's worth mentioning that I also went through the X3 tutorials. Any help would be greatly appreciated.
Edit 1
Taking into account @liliscent's answer, and a few other changes, I was finally able to get it working, here's the correct code:
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <map>
#include <variant>
#include <string>
using namespace std;
namespace x3 = boost::spirit::x3;
int main() {
auto stringRule = x3::rule<class StringClass, string>() = x3::lexeme[x3::alpha >> *x3::alnum];
auto variantRule = x3::rule<class VariantClass, x3::variant<std::string, float>>() = (stringRule | x3::float_);
auto pairRule = x3::rule<class PairClass, pair<int, x3::variant<std::string, float>>>() = x3::int_ >> ':' >> variantRule;
auto mapRule = x3::rule<class MapClass, map<int, x3::variant<std::string, float>>>() = pairRule % ",";
string input = "1 : 1.0, 2 : hello, 3 : world";
map<int, x3::variant<std::string, float>> variantMap;
auto bg = input.begin(), ed = input.end();
auto success = x3::phrase_parse(bg, ed, mapRule, x3::space, variantMap) && bg == ed;
if (!success) cout<<"Parsing not succesfull";
return 0;
}
If you want spirit
to recognize std::pair
and std::map
, you need to include the fusion adaptor for std::pair
:
#include <boost/fusion/adapted/std_pair.hpp>
This should fix your compilation problem. But there are other problems in your code, this rule (*x3::alnum | x3::float_);
won't do what you want, because the left part could directly match empty. You need to rethink how to define this identifier.
Also, better to write pairRule % ","
than pairRule >> * ( "," >> pairRule );
.
And you should pass the input begin as an lvalue iterator, because then it will be advanced during parsing, so that you can check whether the parser has prematurely terminated.