如何修复成员运算符 boost 词法解析器的错误 ->*

问题描述 投票:0回答:1

感谢任何帮助。我正在编写一个解析器,它可以与 GCC 4.9.3 + Boost 1_55 及更早版本一起使用,但不能与 Boost(或 GCC)的更高版本一起使用。

错误是: 错误:与“operator->”不匹配(操作数类型为“const _r1_type {aka const boost::phoenix::actorboost::spirit::attribute<1 >}”和“test::my_config::value_map_t {aka std:” :mapstd::__cxx11::basic_string > >}') _r1 -> my_config::values,qi::_1

代码是:

one_statement = ( key > lit( '=' ) > qi::int_
                      > lit( ';' ) )
    [ if_( phoenix::bind( &value_map_t::count, _r1->* &my_config::values, _1 ) )
        phoenix::bind( &insert_value, _r1, _1, _2 )
    ];


typedef boost::variant<
    std::string,
    double,
    int,
    bool,
    std::vector<double>
    > parsed_types;

typedef value_map_t is std::string<string, parsed_types>;
   value_map_t values;

qi::rule<Iterator, std::pair<std::string, config_section::parsed_types>( my_config* ), skipper_t> one_statement;

这用于按预期进行编译和解析。

boost boost-spirit
1个回答
0
投票

自 c++14 起,

std::map::count
是一个重载函数:https://en.cppreference.com/w/cpp/container/map/count

这就是为什么c++20不允许程序获取标准库函数的地址(参见https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0551r3.pdf 我可以获取标准库中定义的函数的地址吗?)。当然,很多人都会这样做,但正如您所发现的,它会默默地破坏代码。

在你去看之前,新的c++20

std::map::contains
没有同样的问题https://en.cppreference.com/w/cpp/container/map/contains


考虑到很少的背景,我建议进行一些简化。

其一,您希望用一条规则解析所有值类型。其次,您不需要语义操作。如果您坚持,只需检查该密钥是否已存在于

insert_value
辅助函数的一部分即可:

static bool insert_value(my_config* cfg, std::string key, config_section::parsed_types val) {
    if (!cfg)
        return false;
    return cfg->values.emplace(std::move(key), std::move(val)).second; // makes contains(key) check redundant
}

仅当值实际插入时此函数才会返回 true。规则可以变成:

one_statement = (key_ > '=' > value_ > ';')[px::bind(&insert_value, _r1, _1, _2)];

以及调用

count
contains
的整个丑陋混乱。

演示时间

*住在Coliru

#include <boost/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>

namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;

namespace config_section {
    using parsed_types = boost::variant<std::string, double, int, bool, std::vector<double>>;
} // namespace config_section

using value_map_t = std::map<std::string, config_section::parsed_types>;
struct my_config {
    value_map_t values;
};

static bool insert_value(my_config* cfg, std::string key, config_section::parsed_types val) {
    if (!cfg)
        return false;
    return cfg->values.emplace(std::move(key), std::move(val)).second; // makes contains(key) check redundant
}

namespace std { // hack for debug output
    static inline std::ostream& operator<<(std::ostream& os, std::vector<double> const& dd) {
        os << "{";
        for (auto sep = " "; auto d : dd)
            os << std::exchange(sep, ", ") << d;
        return os << " }";
    }
} // namespace std

int main() {
    using Iterator = std::string::const_iterator;
    using namespace qi::labels;
    using skipper_t = qi::blank_type;

    qi::rule<Iterator, std::string()>                             key_, string_;
    qi::rule<Iterator, config_section::parsed_types(), skipper_t> value_;
    qi::rule<Iterator, std::vector<double>(), skipper_t>          vec_;
    qi::rule<Iterator, void(my_config*), skipper_t>               one_statement;
    qi::real_parser<double, qi::strict_real_policies<double>>     strict_double_{};

    key_    = qi::alpha >> +qi::char_("_a-zA-Z0-9");
    vec_    = '{' >> -(qi::double_ % ',') >> '}';
    string_ = '"' >> *('\\' >> qi::char_ | ~qi::char_('"')) >> '"';
    value_  = string_ | vec_ | qi::no_case[qi::bool_] | strict_double_ | qi::int_;

    one_statement = (key_ > '=' > value_ > ';')[px::bind(&insert_value, _r1, _1, _2)];

    my_config cfg;
    for (std::string const input :
         {
             R"(simple_int     = 42;)",
             R"(simple_true    = true;   )",
             R"(simple_false   = False;)",
             R"(simple_string  = "Hello World!"; )",
             R"(escaped_string = "Hello \"Jolly\" World!"; )",
             R"(simple_double  = 42.;)",
             R"(another_double = -inf;)",
             R"(more_double    = 4.2e3;)",
             R"(empty_vec      = {};)",
             R"(filled_vec     = { 123, 234, -4e9, +Inf, NaN, 8e-2, +0 };)",
         }) //
    {
        auto f = begin(input), l = end(input);
        std::cout << " ===== parsed: " << std::boolalpha << phrase_parse(f, l, one_statement(&cfg), qi::blank)
                  << "\n";
        if (f != l)
            std::cout << "     remaining unparsed: " << quoted(std::string(f, l)) << "\n";
    }

    for (auto& [k, v] : cfg.values) {
        std::cout << quoted(k) << "\t -> " << v << "\n";
    }
}

印刷

 ===== parsed: true
 ===== parsed: true
 ===== parsed: true
 ===== parsed: true
 ===== parsed: true
 ===== parsed: true
 ===== parsed: true
 ===== parsed: true
 ===== parsed: true
 ===== parsed: true
"another_double"     -> -inf
"empty_vec"  -> { }
"escaped_string"     -> Hello "Jolly" World!
"filled_vec"     -> { 123, 234, -4e+09, inf, nan, 0.08, 0 }
"more_double"    -> 4200
"simple_double"  -> 42
"simple_false"   -> false
"simple_int"     -> 42
"simple_string"  -> Hello World!
"simple_true"    -> true

奖励:没有凤凰/语义动作

就像我说的,你不需要这些。这是因为

insert
也不会覆盖现有值。因此,进一步简化:

科里鲁直播

#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <iomanip>
#include <map>

namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;

namespace config_section {
    using parsed_types = boost::variant<std::string, double, int, bool, std::vector<double>>;
} // namespace config_section

using value_map_t = std::map<std::string, config_section::parsed_types>;
struct my_config {
    value_map_t values;
};

namespace std { // hack for debug output
    static inline std::ostream& operator<<(std::ostream& os, std::vector<double> const& dd) {
        os << "{";
        for (auto sep = " "; auto d : dd)
            os << std::exchange(sep, ", ") << d;
        return os << " }";
    }
} // namespace std

template <typename Iterator> struct ConfigSection : qi::grammar<Iterator, value_map_t()> {
    ConfigSection() : ConfigSection::base_type(start) {
        key_          = qi::alpha >> +qi::char_("_a-zA-Z0-9");
        vec_          = '{' >> -(qi::double_ % ',') >> '}';
        string_       = '"' >> *('\\' >> qi::char_ | ~qi::char_('"')) >> '"';
        value_        = string_ | vec_ | qi::no_case[qi::bool_] | strict_double_ | qi::int_;
        one_statement = key_ > '=' > value_ > ';';
        config_       = *one_statement;

        start = qi::skip(qi::space)[config_ > qi::eoi];
    }

  private:
    qi::rule<Iterator, value_map_t()> start;

    using Entry     = std::pair<std::string, config_section::parsed_types>;
    using skipper_t = qi::space_type;
    qi::rule<Iterator, value_map_t(), skipper_t>                  config_;
    qi::rule<Iterator, config_section::parsed_types(), skipper_t> value_;
    qi::rule<Iterator, std::vector<double>(), skipper_t>          vec_;
    qi::rule<Iterator, Entry(), skipper_t>                        one_statement;

    // lexemes
    qi::real_parser<double, qi::strict_real_policies<double>> strict_double_;
    qi::rule<Iterator, std::string()>                         key_, string_;
};

int main() {
    static ConfigSection<std::string::const_iterator> const parser;

    std::string const input = R"(
        simple_int     = 42;
        simple_true    = true;
        simple_false   = False;
        simple_string  = "Hello World!";
        escaped_string = "Hello \"Jolly\" World!";
        simple_double  = 42.;
        another_double = -inf;
        more_double    = 4.2e3;
        empty_vec      = {};
        filled_vec     = { 123, 234, -4e9, +Inf, NaN, 8e-2, +0 };
        simple_int     = "WILL IT BLEND?"; )"; // simple_int not overwritten

    my_config cfg;
    std::cout << " ===== parsed: " << std::boolalpha //
              << parse(begin(input), end(input), parser, cfg.values) << "\n";

    for (auto& [k, v] : cfg.values)
        std::cout << quoted(k) << "\t -> " << v << "\n";
}

印刷

 ===== parsed: true
"another_double"     -> -inf
"empty_vec"  -> { }
"escaped_string"     -> Hello "Jolly" World!
"filled_vec"     -> { 123, 234, -4e+09, inf, nan, 0.08, 0 }
"more_double"    -> 4200
"simple_double"  -> 42
"simple_false"   -> false
"simple_int"     -> 42
"simple_string"  -> Hello World!
"simple_true"    -> true
© www.soinside.com 2019 - 2024. All rights reserved.