【问题标题】:Adapt class containing a string member as synthesized attribute包含字符串成员作为合成属性的 Adapt 类
【发布时间】:2014-02-02 14:31:47
【问题描述】:

我正在尝试将字符串解析为自定义类型symbol 的属性,其中包含std::string 成员。我以为我可以在这里使用BOOST_FUSION_ADAPT_STRUCT,但这不起作用。

如果我将规则声明为rule<It, std::string(), space_type>,它会起作用。如果我将它定义为rule<It, symbol(), space_type>,它会失败并显示错误“symbol 中没有类型名称value_type”。我认为 Spirit 正在尝试将值字符逐字符附加到属性,但按预期失败。但是有没有办法让这项工作不添加一个额外的中间规则来捕获std::string 属性?

这是完整的 MWE:

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>

struct symbol 
{ 
    std::string repr; 
};

BOOST_FUSION_ADAPT_STRUCT(symbol, (std::string, repr))

namespace qi = boost::spirit::qi;

template <typename Iterator>
struct test_grammar : qi::grammar<Iterator, symbol(), qi::ascii::space_type> {
    test_grammar() : test_grammar::base_type{start} {
        start = qi::lexeme[+qi::char_("a-z")];
    }

    qi::rule<Iterator, symbol(), qi::ascii::space_type> start;
};

#include <iostream>

auto main() -> int {
    test_grammar<std::string::iterator> grammar{};
    auto input = std::string{"test"};
    auto output = symbol{};
    auto e = end(input);
    if (qi::phrase_parse(begin(input), e, grammar, qi::ascii::space, output))
        std::cout << output.repr;
}

【问题讨论】:

  • 这是 Spirit 中的一个已知限制/错误。我相信当您调整具有单个元素并且该元素是“容器”的结构时会发生这种情况。通常的解决方法是start %= eps &gt;&gt; lexeme[+char_('a', 'z')];,显然这会强制右侧的属性为tuple&lt;std::string&gt;,并且适用于您调整的结构。我会尝试找到一个重复的。
  • @cv_and_he 是的,works 使用该解决方法
  • @cv_and_he 请将其复制到答案中,以便我接受。
  • @sehe 你的“修复”是狡猾的。为什么要删除 string 包含?!为什么要重新排序标题? (事实上​​,现在我看它,为什么任何这些变化?)
  • 如果您不感兴趣,请回滚。其中我也将避免花更多时间回答...?

标签: c++ boost-spirit boost-fusion


【解决方案1】:

正如您从链接的骗子中看到的那样,您可以通过一个合适的qi::eps 来解决这个问题。

    start = qi::eps >> qi::lexeme[+qi::char_("a-z")];

看Live On Coliru

但是,在某些情况下qi::eps 不会保存。 (稍后将尝试查找链接)。因此,我开始支持属性兼容性的“老式方法”:

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

struct symbol 
{ 
    std::string repr; 

    symbol(std::string repr = std::string()) : repr(std::move(repr)) {}
};

namespace qi = boost::spirit::qi;

template <typename Iterator>
struct test_grammar : qi::grammar<Iterator, symbol(), qi::ascii::space_type> {
    test_grammar() : test_grammar::base_type(start) {
        using namespace qi;

        start = as_string[ lexeme[ +char_("a-z") ] ];
    }

    qi::rule<Iterator, symbol(), qi::ascii::space_type> start;
};

#include <iostream>

auto main() -> int {
    test_grammar<std::string::iterator> grammar{};
    auto input = std::string{"test"};
    auto output = symbol{};
    auto e = end(input);
    if (qi::phrase_parse(begin(input), e, grammar, qi::ascii::space, output))
        std::cout << output.repr;
}

这在编译器上也可能更轻一些。也可以看到 Live on Coliru。

如果所有其他方法都失败了,您也可以吃蛋糕,因为属性转换/分配是库中的自定义点。

【讨论】:

    猜你喜欢
    • 2020-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-03
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多