草庐IT

c++ - Boost Spirit X3 无法编译具有可变因子的重复指令

coder 2023-11-14 原文

我正在尝试使用具有可变重复因子的 Boost Spirit X3 指令 repeat。基本思想是 header +有效载荷,其中 header 指定有效载荷的大小。一个简单的例子“3 1 2 3”被解释为 header = 3, data= {1, 2, 3}(3 个整数)。

我只能从灵气文档中找到例子。它使用 boost phoenix 引用来包装变量因子:http://www.boost.org/doc/libs/1_50_0/libs/spirit/doc/html/spirit/qi/reference/directive/repeat.html

std::string str;
int n;
test_parser_attr("\x0bHello World",
    char_[phx::ref(n) = _1] >> repeat(phx::ref(n))[char_], str);
std::cout << n << ',' << str << std::endl;  // will print "11,Hello World"

我为 spirit x3 编写了以下简单示例,但运气不佳:

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
#include <iostream>

namespace x3 = boost::spirit::x3;
using x3::uint_;
using x3::int_;
using x3::phrase_parse;
using x3::repeat;
using x3::space;
using std::string;
using std::cout;
using std::endl;

int main( int argc, char **argv )
{
  string data("3 1 2 3");
  string::iterator begin = data.begin();
  string::iterator end = data.end();

  unsigned int n = 0;

  auto f = [&n]( auto &ctx ) { n = x3::_attr(ctx); };
  bool r = phrase_parse( begin, end, uint_[f] >> repeat(boost::phoenix::ref(n))[int_], space );
  if ( r && begin == end  )
    cout << "Parse success!" << endl; 
  else
    cout << "Parse failed, remaining: " << string(begin,end) << endl;

  return 0;
}

使用 boost 1.59.0 和 clang++(标志:-std=c++14)编译上面的代码会得到以下结果:

boost_1_59_0/boost/spirit/home/x3/directive/repeat.hpp:72:47: error: no matching constructor for

      initialization of 'proto_child0' (aka 'boost::reference_wrapper<unsigned int>')

            typename RepeatCountLimit::type i{};

如果我硬编码 repeat(3) 而不是 repeat(boost::phoenix::ref(n)) 它可以正常工作,但这不是一个可能的解决方案因为它应该支持可变的重复因子。

使用 repeat(n) 编译成功完成,但解析失败,输出如下: “解析失败,剩余:1 2 3”

查看 boost/spirit/home/x3/directive/repeat.hpp:72 的源代码,它调用模板类型 RepeatCountLimit::type 的空构造函数变量 i,然后在 for 循环期间赋值,遍历最小值和最大值。然而,由于该类型是一个引用,它应该在构造函数中初始化,因此编译失败。查看之前库版本的等效源代码 boost/spirit/home/qi/directive/repeat.hpp:162 直接赋值:

        typename LoopIter::type i = iter.start();

我不确定我在这里做错了什么,或者 x3 目前是否不支持可变重复因子。我将不胜感激一些帮助解决这个问题。谢谢。

最佳答案

根据我收集的信息,阅读源代码和邮件列表,Phoenix 根本没有集成到 X3 中:原因是 c++14 使它的大部分都过时了。

我同意这留下了一些 Qi 曾经有优雅解决方案的地方,例如eps(DEFERRED_CONDITION) , lazy(*RULE_PTR) (Nabialek trick),确实是这种情况。

Spirit X3 仍在开发中,所以我们可能会看到这个添加¹

目前,Spirit X3 拥有一种用于有状态上下文的通用工具。这基本上取代了 locals<> ,在某些情况下继承了参数,并且在这种特殊情况下也可以/使/验证元素的数量:

  • x3::with ²

以下是您可以如何使用它:

with<_n>(std::ref(n)) 
    [ omit[uint_[number] ] >> 
    *(eps [more] >> int_) >> eps [done] ]

在这里,_n是一种标记类型,用于标识要使用 get<_n>(cxtx) 检索的上下文元素.

Note, currently we have to use a reference-wrapper to an lvalue n because with<_n>(0u) would result in constant element inside the context. I suppose this, too, is a QoI that may be lifted as X# matures

现在,对于语义 Action :

unsigned n;
struct _n{};

auto number = [](auto &ctx) { get<_n>(ctx).get() = _attr(ctx); };

这会将解析后的无符号数存储到上下文中。 (事实上,由于 ref(n) 绑定(bind),它现在实际上不是上下文的一部分,如前所述)

auto more   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) >  _val(ctx).size(); };

在这里我们检查我们实际上不是“满的”——即允许

更多的整数
auto done   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) == _val(ctx).size(); };

这里我们检查我们是否“满”——即不允许更多的整数

综合起来:

Live On Coliru

#include <string>
#include <iostream>
#include <iomanip>

#include <boost/spirit/home/x3.hpp>

int main() {
    for (std::string const input : { 
            "3 1 2 3", // correct
            "4 1 2 3", // too few
            "2 1 2 3", // too many
            // 
            "   3 1 2 3   ",
        })
    {
        std::cout << "\nParsing " << std::left << std::setw(20) << ("'" + input + "':");

        std::vector<int> v;

        bool ok;
        {
            using namespace boost::spirit::x3;

            unsigned n;
            struct _n{};

            auto number = [](auto &ctx) { get<_n>(ctx).get() = _attr(ctx); };
            auto more   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) >  _val(ctx).size(); };
            auto done   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) == _val(ctx).size(); };

            auto r = rule<struct _r, std::vector<int> > {} 
                  %= with<_n>(std::ref(n)) 
                        [ omit[uint_[number] ] >> *(eps [more] >> int_) >> eps [done] ];

            ok = phrase_parse(input.begin(), input.end(), r >> eoi, space, v);
        }

        if (ok) {
            std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout << v.size() << " elements: ", " "));
        } else {
            std::cout << "Parse failed";
        }
    }
}

打印:

Parsing '3 1 2 3':          3 elements: 1 2 3 
Parsing '4 1 2 3':          Parse failed
Parsing '2 1 2 3':          Parse failed
Parsing '   3 1 2 3   ':    3 elements: 1 2 3 

¹ 在 [spirit-general] 邮件列表中提供您的支持/发言 :)

² 找不到合适的文档链接,但在一些示例中使用了它

关于c++ - Boost Spirit X3 无法编译具有可变因子的重复指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33624149/

有关c++ - Boost Spirit X3 无法编译具有可变因子的重复指令的更多相关文章

  1. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  4. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  5. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  6. ruby-on-rails - 无法在centos上安装therubyracer(V8和GCC出错) - 2

    我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e

  7. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  8. ruby - 无法覆盖 irb 中的 to_s - 2

    我在pry中定义了一个函数:to_s,但我无法调用它。这个方法去哪里了,怎么调用?pry(main)>defto_spry(main)*'hello'pry(main)*endpry(main)>to_s=>"main"我的ruby版本是2.1.2看了一些答案和搜索后,我认为我得到了正确的答案:这个方法用在什么地方?在irb或pry中定义方法时,会转到Object.instance_methods[1]pry(main)>defto_s[1]pry(main)*'hello'[1]pry(main)*end=>:to_s[2]pry(main)>defhello[2]pry(main)

  9. ruby - 无法在 60 秒内获得稳定的 Firefox 连接 (127.0.0.1 :7055) - 2

    我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类

  10. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

随机推荐