Ошибки компиляции C ++ Spirit X3 Нет жизнеспособного перегруженного =, Нет подходящей функции для вызова move_to

Майкл Кейсс выступил с докладом о Spirit X3: https://www.youtube.com/watch?v=xSBWklPLRvw. Я пытался перевести презентацию в рабочий код, но у меня есть ошибки компиляции, которые включают «No viable overloaded» = «» и «Нет вызова соответствующей функции для move_to». Правильно ли определена моя фраза_parse (последняя строка)? Есть ли очевидные ошибки?

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/container/stable_vector.hpp>

#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <map>

namespace client { namespace ast
{
namespace x3 = boost::spirit::x3;

using string_t = std::string;
using double_t = double;
using float_t = double;
using int_t = int64_t;
using bool_t = bool;
struct null_t {};

class value;

using object_t = std::map<std::string, value>;
using object_member_t = object_t::value_type;
using array_t = boost::container::stable_vector<value>;

class value : public x3::variant<null_t, bool_t, string_t, int_t, double_t, object_t, array_t>
{
public:
using value_type = value;
using base_type::base_type;
using base_type::operator=;
value(null_t val = null_t{}) : base_type(val) {}
value(char const* val)       : base_type(string_t(val)) {}

template<typename T>
value(T val, typename std::enable_if<std::is_floating_point<T>::value>::type) : base_type(double_t{val}) {}

template<typename T>
value(T val, typename std::enable_if<std::is_integral<T>::value::type>) : base_type(int_t{val}) {}

};

struct json_class;
using json_type = x3::rule<json_class, value>;
json_type const json = "json";
BOOST_SPIRIT_DECLARE(json_type);

// identifier_class id
// identifier_type  type
// identifier_def   rule def
// identifier       the rule

struct value_class;
struct object_class;
struct member_pair_class;
struct array_class;

using value_type = x3::rule<value_class, value>;
using object_type = x3::rule<object_class, object_t>;
using member_pair_type = x3::rule<member_pair_class, object_member_t>;
using array_type = x3::rule<array_class, array_t>;

value_type const value = "value";
object_type const object = "object";
member_pair_type const member_pair = "member_pair";
array_type const array = "array";

auto const append = [](auto& ctx){ _val(ctx) += _attr(ctx); };

using uchar = unsigned char;

x3::uint_parser<uchar, 16, 4, 4> const hex4 = {};

auto push_esc = [](auto& ctx)
{
auto& utf8 = _val(ctx);
switch (_attr(ctx))
{
case '"' : utf8 += '"';   break;
case '\\': utf8 += '\\';  break;
case '/' : utf8 += '/';   break;
case 'b' : utf8 += '\b';  break;
case 'f' : utf8 += '\f';  break;
case 'n' : utf8 += '\n';  break;
case 'r' : utf8 += '\r';  break;
case 't' : utf8 += '\t';  break;
}
};

auto push_utf8 = [](auto& ctx)
{
typedef std::back_insert_iterator<std::string> insert_iter;
insert_iter out_iter(_val(ctx));
boost::utf8_output_iterator<insert_iter> utf8_iter(out_iter);
*utf8_iter++ = _attr(ctx);
};

auto const escape = ('u' > hex4)            [push_utf8]
| x3::char_("\"\\/bfnrt") [push_esc];

auto const char_esc = '\\' > escape;

auto const double_quoted = x3::lexeme[ '"' > *(char_esc) | (x3::char_("\x20\x21\x23-\x5b\x5d\x7e")) [append]  > '"' ];

struct unicode_string_class;
using unicode_string_type = x3::rule<unicode_string_class, std::string>;
unicode_string_type const unicode_string = "unicode_string";
auto const unicode_string_def = double_quoted;
BOOST_SPIRIT_DEFINE(unicode_string);

auto const null_value = x3::lit("null") >> x3::attr(null_t{});
x3::int_parser<int64_t> const int_ = {};
x3::ascii::bool_type const bool_value = {};

auto const object_def = x3::lit('{') >> -(member_pair % ',') >> x3::lit('}');

auto const member_pair_def = unicode_string >> ':' >> value;

auto const array_def = x3::lit('[') >> -(value % ',') >> x3::lit(']');

auto const value_def = null_value | bool_value | object | array | unicode_string
| x3::lexeme[!('+' | (-x3::lit('-') >> '0' >> x3::digit)) >> x3::int_ >> !x3::char_(".eE")]
| x3::lexeme[!('+' | (-x3::lit('-') >> '0' >> x3::digit)) >> x3::double_ ];

BOOST_SPIRIT_DEFINE(value, object, member_pair, array);
}
}

int main(int argc, char **argv)
{

namespace x3 = boost::spirit::x3;

std::string storage; // We will read the contents here.

using boost::spirit::x3::ascii::space;
std::string::const_iterator iter = storage.begin();
std::string::const_iterator iter_end = storage.end();

client::ast::object_t o;
auto const grammar = client::ast::value;

bool r = phrase_parse(iter, iter_end, grammar, space, o);
}

2

Решение

Ладно, мне пришлось сгладить немало ошибок / причуд.

Часть моего глажения была уборкой вещей, которые я обычно делаю по-другому. Вот рабочий результат:

Жить на Колиру

#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/container/stable_vector.hpp>

#include <iterator>
#include <fstream>
#include <string>
#include <map>

namespace client {
namespace x3 = boost::spirit::x3;

namespace ast
{
using string_t = std::string;
using double_t = double;
using float_t = double;
using int_t = int64_t;
using bool_t = bool;
struct null_t {};

class value;

using object_t        = std::map<std::string, value>;
using object_member_t = object_t::value_type;
using member_pair_t   = std::pair<object_t::key_type, object_t::mapped_type>;
using array_t         = boost::container::stable_vector<value>;

class value : public x3::variant<null_t, bool_t, string_t, int_t, double_t, object_t, array_t>
{
public:
using value_type = value;
using base_type::base_type;
using base_type::operator=;
value(null_t val = null_t{}) : base_type(val) {}
value(char const* val)       : base_type(string_t(val)) {}

template<typename T>
value(T val, typename std::enable_if<std::is_floating_point<T>::value>::type) : base_type(double_t{val}) {}

template<typename T>
value(T val, typename std::enable_if<std::is_integral<T>::value::type>) : base_type(int_t{val}) {}

};

}

namespace parser
{
auto const append = [](auto& ctx){ x3::_val(ctx) += x3::_attr(ctx); };

using uchar = unsigned char;

x3::uint_parser<uchar, 16, 4, 4> const hex4 = {};

auto push_esc = [](auto& ctx) {
auto& utf8 = x3::_val(ctx);
switch (x3::_attr(ctx))
{
case '"' : utf8 += '"';   break;
case '\\': utf8 += '\\';  break;
case '/' : utf8 += '/';   break;
case 'b' : utf8 += '\b';  break;
case 'f' : utf8 += '\f';  break;
case 'n' : utf8 += '\n';  break;
case 'r' : utf8 += '\r';  break;
case 't' : utf8 += '\t';  break;
}
};

auto push_utf8 = [](auto& ctx) {
typedef std::back_insert_iterator<std::string> insert_iter;
insert_iter out_iter(x3::_val(ctx));
boost::utf8_output_iterator<insert_iter> utf8_iter(out_iter);
*utf8_iter++ = x3::_attr(ctx);
};

auto const escape = ('u' > hex4)            [push_utf8]
| x3::char_("\"\\/bfnrt") [push_esc];

auto const char_esc = '\\' > escape;

auto const double_quoted = x3::lexeme[
'"' > *(char_esc | (x3::char_("\x20\x21\x23-\x5b\x5d-\x7e") [append])) > '"'
];

auto const unicode_string
= x3::rule<struct unicode_string_class, std::string> { "unicode_string" }
= double_quoted;

auto const null_value = x3::lit("null") >> x3::attr(ast::null_t{});

x3::ascii::bool_type const bool_value = {};

using value_type = x3::rule<struct value_class, ast::value>;
static value_type const value = "value";

auto const member_pair = x3::rule<struct member_pair_class, ast::member_pair_t> { "member_pair" }
= unicode_string >> ':' >> value;

auto const object = x3::rule<struct object_class, ast::object_t> { "object" }
= x3::lit('{') >> -(member_pair % ',') >> x3::lit('}');

auto const array = x3::rule<struct array_class, ast::array_t> { "array" }
= x3::lit('[') >> -(value % ',') >> x3::lit(']');

x3::real_parser<double, x3::strict_real_policies<double> > const double_ = {};
x3::int_parser<int64_t> const int_                                       = {};

auto const value_def = null_value | bool_value | object | array | unicode_string | double_ | int_ ;

BOOST_SPIRIT_DEFINE(value)

auto const json = x3::skip(x3::ascii::space) [ value ];
}
}

int main()
{
std::string storage = R"({ "check": [ 1,2,3, null, true ], "more": { "nested" : "values" } })";

client::ast::value o;
return parse(storage.begin(), storage.end(), client::parser::json, o)? 0 : 255;
}

Выведение:

<value>
<try>{ "check": [ 1,2,3, </try>
<object>
<try>{ "check": [ 1,2,3, </try>
<member_pair>
<try> "check": [ 1,2,3, n</try>
<unicode_string>
<try> "check": [ 1,2,3, n</try>
<success>: [ 1,2,3, null, tru</success>
<attributes>[c, h, e, c, k]</attributes>
</unicode_string>
<value>
<try> [ 1,2,3, null, true</try>
<object>
<try>[ 1,2,3, null, true </try>
<fail/>
</object>
<array>
<try>[ 1,2,3, null, true </try>
<value>
<try> 1,2,3, null, true ]</try>
<object>
<try>1,2,3, null, true ],</try>
<fail/>
</object>
<array>
<try>1,2,3, null, true ],</try>
<fail/>
</array>
<unicode_string>
<try>1,2,3, null, true ],</try>
<fail/>
</unicode_string>
<success>,2,3, null, true ], </success>
<attributes>1</attributes>
</value>
<value>
<try>2,3, null, true ], "</try>
<object>
<try>2,3, null, true ], "</try>
<fail/>
</object>
<array>
<try>2,3, null, true ], "</try>
<fail/>
</array>
<unicode_string>
<try>2,3, null, true ], "</try>
<fail/>
</unicode_string>
<success>,3, null, true ], "m</success>
<attributes>2</attributes>
</value>
<value>
<try>3, null, true ], "mo</try>
<object>
<try>3, null, true ], "mo</try>
<fail/>
</object>
<array>
<try>3, null, true ], "mo</try>
<fail/>
</array>
<unicode_string>
<try>3, null, true ], "mo</try>
<fail/>
</unicode_string>
<success>, null, true ], "mor</success>
<attributes>3</attributes>
</value>
<value>
<try> null, true ], "more</try>
<success>, true ], "more": { </success>
<attributes></attributes>
</value>
<value>
<try> true ], "more": { "</try>
<success> ], "more": { "neste</success>
<attributes>1</attributes>
</value>
<success>, "more": { "nested"</success>
<attributes>[1, 2, 3, , 1]</attributes>
</array>
<success>, "more": { "nested"</success>
<attributes>[1, 2, 3, , 1]</attributes>
</value>
<success>, "more": { "nested"</success>
<attributes>[[c, h, e, c, k], [1, 2, 3, , 1]]</attributes>
</member_pair>
<member_pair>
<try> "more": { "nested" </try>
<unicode_string>
<try> "more": { "nested" </try>
<success>: { "nested" : "valu</success>
<attributes>[m, o, r, e]</attributes>
</unicode_string>
<value>
<try> { "nested" : "value</try>
<object>
<try>{ "nested" : "values</try>
<member_pair>
<try> "nested" : "values"</try>
<unicode_string>
<try> "nested" : "values"</try>
<success> : "values" } }</success>
<attributes>[n, e, s, t, e, d]</attributes>
</unicode_string>
<value>
<try> "values" } }</try>
<object>
<try>"values" } }</try>
<fail/>
</object>
<array>
<try>"values" } }</try>
<fail/>
</array>
<unicode_string>
<try>"values" } }</try>
<success> } }</success>
<attributes>[v, a, l, u, e, s]</attributes>
</unicode_string>
<success> } }</success>
<attributes>[v, a, l, u, e, s]</attributes>
</value>
<success> } }</success>
<attributes>[[n, e, s, t, e, d], [v, a, l, u, e, s]]</attributes>
</member_pair>
<success> }</success>
<attributes>[[[n, e, s, t, e, d], [v, a, l, u, e, s]]]</attributes>
</object>
<success> }</success>
<attributes>[[[n, e, s, t, e, d], [v, a, l, u, e, s]]]</attributes>
</value>
<success> }</success>
<attributes>[[m, o, r, e], [[[n, e, s, t, e, d], [v, a, l, u, e, s]]]]</attributes>
</member_pair>
<success></success>
<attributes>[[[c, h, e, c, k], [1, 2, 3, , 1]], [[m, o, r, e], [[[n, e, s, t, e, d], [v, a, l, u, e, s]]]]]</attributes>
</object>
<success></success>
<attributes>[[[c, h, e, c, k], [1, 2, 3, , 1]], [[m, o, r, e], [[[n, e, s, t, e, d], [v, a, l, u, e, s]]]]]</attributes>
</value>

Некоторые заметки:

  1. Неудачное назначение было из-за правила парсера value приводит к объекту типа valueне object_t

  2. object_member_t это пара с std::string const first_type. К сожалению. Это не может быть назначено либо. Итак, создайте свой собственный тип пары и используйте его:

    using member_pair_t   = std::pair<object_t::key_type, object_t::mapped_type>;
    
  3. Мой g ++ 5, похоже, имел проблемы с поиском ADL _attr а также _val если оставить неквалифицированным Я не уверен, что это проблема компилятора, или что. Я просто пошел с x3::_attr а также x3::_val теперь

  4. В определениях правил было несколько пропущенных паренов, что затрудняло чтение / проверку правил. Добавил их

  5. unicode_string оказалось сломанным (см. ниже)

  6. int_parser<int64_t> никогда не использовался (да?) Используй это 🙂

  7. Разбор номера не работал. В то же время это выглядело слишком сложным. Я предлагаю использовать double_ | int_ где double_ использует строгую политику:

    x3::real_parser<double, x3::strict_real_policies<double> > const double_ = {};
    

Вопросы стиля:

  1. Не заставляйте звонящего отвечать за выбор шкипера. В конце концов, если вы используете x3::char_("+8") как шкипер, все будет или сломаться или не сможет быть JSON? Я предлагаю правило верхнего уровня, чтобы просто представить шкипера:

    auto const json = x3::skip(x3::ascii::space) [ value ];
    
  2. Тестовый драйвер может быть намного менее шумным:

    std::string storage = R"({ "check": [ 1,2,3, null, true ], "more": { "nested" : "values" } })";
    
    client::ast::value o;
    bool r = parse(storage.begin(), storage.end(), client::parser::json, o);
    
  3. Я удалил шумный _class / _type / _def dance для правил, которые не используются «exernally» (в этом простом примере кода все, что не используется рекурсивно: value)

  4. использование BOOST_SPIRIT_X3_DEBUG чтобы увидеть, что происходит 🙂 (это позволило мне обнаружить ошибку в x3::char_("\x20\x21\x23-\x5b\x5d\x7e")Видишь пропавшую тире?)

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]