草庐IT

c++ - 如何为 boost::program_options 的位置选项添加描述?

coder 2024-02-04 原文

我想用 boost_program_options 创建一个位置列表程序选项,不允许命名程序选项(如 --files)。

我有以下代码片段:

#include <boost/program_options.hpp>
#include <iostream>
#include <string>
#include <vector>

namespace po = boost::program_options;

int main(int argc, const char* argv[]) {
  po::options_description desc("Allowed options");
  desc.add_options()("help", "produce help message")
  ( "files", po::value<std::vector<std::string>>()->required(), "list of files");

  po::positional_options_description pos;
  pos.add("files", -1);

  po::variables_map vm;
  try {
    po::store(po::command_line_parser(argc, argv).options(desc).positional(pos).run(), vm);
    po::notify(vm);
  } catch(const po::error& e) {
    std::cerr << "Couldn't parse command line arguments properly:\n";
    std::cerr << e.what() << '\n' << '\n';
    std::cerr << desc << '\n';
    return 1;
  }

  if(vm.count("help") || !vm.count("files")) {
    std::cout << desc << "\n";
    return 1;
  }
}

问题是我可以读取文件列表作为位置参数列表,如下所示:

./a.out file1 file2 file3

但不幸的是也喜欢这个(我想禁用它)

./a.out --files file1 file2 file3

问题还在于产生的帮助:

./a.out
Couldn't parse command line arguments properly:
the option '--files' is required but missing

Allowed options:
  --help                produce help message
  --files arg           list of files

所以我想要的场景更像是(类似):

./a.out
Couldn't parse command line arguments properly:
[FILES ...] is required but missing

Allowed options:
  --help                produce help message
  --optionx             some random option used in future
  [FILE ...]            list of files

在我从 desc.add_option()(...) 中删除 files 选项后,它停止工作,所以我相信我需要它。

最佳答案

关于标题中提出的问题,“如何为 boost::program_options 的位置选项添加描述?”,有 no functionality图书馆为此提供。您需要自己处理该部分。

至于问题的正文......这是可能的,但以一种稍微迂回的方式。

位置选项将每个位置映射到一个名称,名称需要存在。从我在代码 ( cmdline.cpp ) 中得知的情况来看,不会为位置参数设置 unregistered 标志。 [ 1 ], [ 2 ]

所以,为了做你想做的,我们可以做以下事情:

  • 在帮助中隐藏 --files 选项。您需要自己为位置选项显示适当的帮助,但这与以前没有什么不同。
  • variables_map 的已解析选项的解析和存储之间添加我们自己的验证。

从帮助中隐藏--files

在这里我们利用了我们可以创建复合 options_description 的事实使用 add(...)成员函数:

po::options_description desc_1;
// ...
po::options_description desc_2;
// ...
po::options_description desc_composite;
desc_composite.add(desc_1).add(desc_2);

因此,我们可以将 files 选项放入隐藏的 options_description 中,并创建一个仅用于解析阶段的组合。 (见下面的代码)

防止显式--files

我们需要在解析选项列表和将它们存储到 variables_map 之间拦截选项列表。

command_line_parserrun() 方法返回basic_parsed_options 的一个实例,其成员 options 包含 basic_option 的 vector 秒。每个解析参数都有一个元素,任何位置选项都从 0 开始枚举,任何非位置选项的位置都是 -1。当我们将 --files 视为显式(非位置)参数时,我们可以使用它来执行我们自己的验证并引发错误。

示例源代码

See on Coliru

#include <boost/program_options.hpp>
#include <iostream>
#include <string>
#include <vector>

namespace po = boost::program_options;

int main(int argc, const char* argv[])
{
    std::vector<std::string> file_names;

    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "produce help message")
        ("test", "test option");

    std::string const FILES_KEY("files");

    // Hide the `files` options in a separate description
    po::options_description desc_hidden("Hidden options");
    desc_hidden.add_options()
        (FILES_KEY.c_str(), po::value(&file_names)->required(), "list of files");

    // This description is used for parsing and validation
    po::options_description cmdline_options;
    cmdline_options.add(desc).add(desc_hidden);

    // And this one to display help
    po::options_description visible_options;
    visible_options.add(desc);

    po::positional_options_description pos;
    pos.add(FILES_KEY.c_str(), -1);

    po::variables_map vm;
    try {
        // Only parse the options, so we can catch the explicit `--files`
        auto parsed = po::command_line_parser(argc, argv)
            .options(cmdline_options)
            .positional(pos)
            .run();

        // Make sure there were no non-positional `files` options
        for (auto const& opt : parsed.options) {
            if ((opt.position_key == -1) && (opt.string_key == FILES_KEY)) {
                throw po::unknown_option(FILES_KEY);
            }
        }

        po::store(parsed, vm);
        po::notify(vm);
    } catch(const po::error& e) {
        std::cerr << "Couldn't parse command line arguments properly:\n";
        std::cerr << e.what() << '\n' << '\n';
        std::cerr << visible_options << '\n';
        return 1;
    }

    if (vm.count("help") || !vm.count("files")) {
        std::cout << desc << "\n";
        return 1;
    }

    if (!file_names.empty()) {
        std::cout << "Files: \n";
        for (auto const& file_name : file_names) {
            std::cout << " * " << file_name << "\n";
        }
    }
}

测试输出

有效选项:

>example a b c --test d e
Files:
 * a
 * b
 * c
 * d
 * e

无效选项:

>example a b c --files d e
Couldn't parse command line arguments properly:
unrecognised option 'files'


Allowed options:
  --help                 produce help message
  --test                 test option

关于c++ - 如何为 boost::program_options 的位置选项添加描述?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39932089/

有关c++ - 如何为 boost::program_options 的位置选项添加描述?的更多相关文章

  1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  2. ruby - 将 Bootstrap Less 添加到 Sinatra - 2

    我有一个ModularSinatra应用程序,我正在尝试将Bootstrap添加到应用程序中。get'/bootstrap/application.css'doless:"bootstrap/bootstrap"end我在views/bootstrap中有所有less文件,包括bootstrap.less。我收到这个错误:Less::ParseErrorat/bootstrap/application.css'reset.less'wasn'tfound.Bootstrap.less的第一行是://CSSReset@import"reset.less";我尝试了所有不同的路径格式,但它

  3. ruby - 如何为 emacs 安装 ruby​​-mode - 2

    我刚刚为fedora安装了emacs。我想用emacs编写ruby。为ruby​​提供代码提示、代码完成类型功能所需的工具、扩展是什么? 最佳答案 ruby-mode已经包含在Emacs23之后的版本中。不过,它也可以通过ELPA获得。您可能感兴趣的其他一些事情是集成RVM、feature-mode(Cucumber)、rspec-mode、ruby-electric、inf-ruby、rinari(用于Rails)等。这是我当前用于Ruby开发的Emacs配置:https://github.com/citizen428/emacs

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

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

  5. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  6. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  7. ruby - Capistrano 3 在任务中更改 ssh_options - 2

    我尝试使用不同的ssh_options在同一阶段运行capistranov.3任务。我的production.rb说:set:stage,:productionset:user,'deploy'set:ssh_options,{user:'deploy'}通过此配置,capistrano与用户deploy连接,这对于其余的任务是正确的。但是我需要将它连接到服务器中配置良好的an_other_user以完成一项特定任务。然后我的食谱说:...taskswithoriginaluser...task:my_task_with_an_other_userdoset:user,'an_othe

  8. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  9. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  10. ruby - 可以通过多少种方法将方法添加到 ruby​​ 对象? - 2

    当谈到运行时自省(introspection)和动态代码生成时,我认为ruby​​没有任何竞争对手,可能除了一些lisp方言。前几天,我正在做一些代码练习来探索ruby​​的动态功能,我开始想知道如何向现有对象添加方法。以下是我能想到的3种方法:obj=Object.new#addamethoddirectlydefobj.new_method...end#addamethodindirectlywiththesingletonclassclass这只是冰山一角,因为我还没有探索instance_eval、module_eval和define_method的各种组合。是否有在线/离线资

随机推荐