【问题标题】:Using boost spirit expression使用提升精神表达
【发布时间】:2021-10-04 14:28:47
【问题描述】:

我的boost精神表达有问题。原始代码比较复杂,我做了一个小快照。 此代码在调试模式下按预期工作,并且在发布时没有,解析返回 false,但应该返回 true(我正在 Visual Studio 2019 上对其进行测试)

int main() {
    namespace qi = boost::spirit::qi;

    auto X19 = qi::lit("                   ") | qi::lit(" 0.000000000000D+00");
    auto i4 = qi::uint_;
    string str = "1234                   1234";
    auto f = str.cbegin();
    auto l = str.cend();
    bool ret = qi::parse(f, l, ( i4 >> X19 >> i4 ));
}

下一个快照在两种模式下都运行良好:

int main() {
    namespace qi = boost::spirit::qi;

    auto i4 = qi::uint_;
    string str = "1234                   1234";
    auto f = str.cbegin();
    auto l = str.cend();
    bool ret = qi::parse(f, l, ( i4 >> (qi::lit("                   ") | qi::lit(" 0.000000000000D+00")) >> i4 ));
    cout << ret << endl;
    return ret;
}

我做错了什么,以这种方式划分长表达式? 谢谢

【问题讨论】:

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


    【解决方案1】:

    你用 Spirit 的 Proto 表达式一头扎进了悬空的临时陷阱。简短的规则是:

    不要在 Spirit 表达式中使用 auto

    你的节目展示了Undefined Behaviour:看到它Live On Compiler Explorer


    解决方法涉及BOOST_SPIRIT_AUTOqi::copy(在最近的增强版本发布之前,它们只能作为boost::proto::deep_copy 使用)。

    已修复

    Live On Coliru

    #include <boost/spirit/include/qi.hpp>
    
    int main() {
        namespace qi = boost::spirit::qi;
    
        auto i4 = qi::copy(qi::uint_);
        auto X19 = qi::copy(               //
              qi::lit("                   ") //
            | qi::lit(" 0.000000000000D+00")//
            );
    
        std::string str = "1234                   1234";
        auto        f = str.cbegin(), l = str.cend();
    
        bool ret = qi::parse(f, l, (i4 >> X19 >> i4));
        std::cout << std::boolalpha << ret << "\n";
    }
    

    打印

    true
    

    奖金

    1. 请注意,Spirit X3 不再有此限制/问题:Live On Coliru

      #include <boost/spirit/home/x3.hpp>
      
      int main() {
          namespace x3 = boost::spirit::x3;
      
          auto i4 = x3::uint_;
          auto X19 =                           //
              x3::lit("                   ")   //
              | x3::lit(" 0.000000000000D+00") //
              ;
      
          std::string str = "1234                   1234";
          auto        f = str.cbegin(), l = str.cend();
      
          bool ret = parse(f, l, (i4 >> X19 >> i4));
          std::cout << std::boolalpha << ret << "\n";
      }
      
    2. 你可能真的想要

      qi::uint_parser<int, 10, 4, 4> i4;
      // or
      x3::uint_parser<int, 10, 4, 4> i4;
      
    3. 看起来好像您在解析 COBOL 之类的(固定宽度)记录,在这种情况下,我认为有更好的方法来组织您的语法以使其可靠。

    【讨论】:

    • 添加了 3 个附注
    • 添加了 -fsanitize=address 在编译器资源管理器上实时输出 godbolt.org/z/KhGeaGK8j
    • 非常感谢,是的,原始代码就是这样,我必须为实数编写自定义解析器,它检查整个长度和小数部分的位数,我没有没有找到怎么做。我是否错过了文档中有关“自动”和“复制”的内容?
    • 也许你应该把它作为一个单独的问题来问
    • 我花了一个小时创建这个作为起点:coliru.stacked-crooked.com/a/462f73b9f43aeff6 所以如果你问这个特定的问题,它可能对其他人非常有帮助:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 2013-06-09
    • 1970-01-01
    相关资源
    最近更新 更多