c++ - 使用 Boost.Program_options 创建前缀命令

标签 c++ boost command-line-arguments boost-program-options

我想创建一个前缀程序,如 strace使用Boost.Program_options。前缀的意思是我的程序放在另一个任意的command [args]前面。因此,我的程序应该接受一些已定义的关键字参数/标志。第一个位置参数指示我要添加前缀的命令。该命令本身可能后面跟着我不知道的参数的任意组合,并且可能与我的程序的参数重叠。因此,第一个位置参数以及其后的任何内容都应以 std::vector<std::string> 结尾。 :

./foo --bar 13 command1                      # Should run fine
./foo command2 positional                    # Should run fine
./foo --bar 13 command3 --unknown argument   # Should run fine
./foo --unknown command4                     # should fail
./foo --bar 13 command5 --bar 42             # Should work but set bar to 13
./foo command6 --bar 42                      # Should not set bar at all
./foo --bar 13 -- command7 --bar 42 --unknown argument     # Should work

正确的用法是首先指定任何已定义的关键字 基本上在正确的形式中,首先有一些我定义的应该采取任意数量的预定义

我尝试了两种方法:

1) 使用allow_unregistered :

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

namespace po = boost::program_options;

int main(int argc, const char** argv)
{
    int bar = 0;
    po::options_description desc("Allowed options");

    desc.add_options()
            ("bar", po::value(&bar), "bar");


    po::variables_map vm;
    po::parsed_options parsed =
        po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
    po::store(parsed, vm);
    po::notify(vm);

    auto command = po::collect_unrecognized(parsed.options, po::include_positional);
    std::cout << "bar: " << bar << ", command:";
    for (const auto& c : command) std::cout << " " << c;
    std::cout << std::endl;
}

命令 4、5、6 失败

2) 一种位置选项,出现次数不限

std::vector<std::string> command;

desc.add_options()
        ("bar", po::value(&bar), "bar")
        ("command", po::value(&command));

po::positional_options_description p;
p.add("command", -1);

po::variables_map vm;
po::parsed_options parsed =
    po::command_line_parser(argc, argv).options(desc).positional(p).run();
po::store(parsed, vm);
po::notify(vm);

命令 3、5、6 失败。

最佳答案

Boost Trac 上有一个对此的功能请求,包括补丁:https://svn.boost.org/trac/boost/ticket/6991 。票证上没有太大变化,但补丁仍然完全适用于 Boost(截至 1.61.0,最新版本)。

如果您的构建系统允许,您可以将补丁应用到本地的 Boost 拷贝;否则,您可以从 cmdline.hppdetail/cmdline.hppcmdline 中提取 boost::program_options::detail::cmdline .cpp,进入您自己的命名空间,修补该组件,并使用修补后的组件代替 boost::program_options::cmdline

还有一个选择是使用 extra_style_parser 参数来破解 boost::program_options::detail::cmdline 的行为:

po::detail::cmdline cmdline(argc, argv);
cmdline.set_options_description(desc);
cmdline.set_positional_options(p);
std::vector<po::detail::cmdline::style_parser> style_parsers{
    [&](auto& args) { return cmdline.parse_long_option(args); },
    [&](auto& args) { return cmdline.parse_short_option(args); }};
cmdline.extra_style_parser([&](std::vector<std::string>& args) {
    auto const current_size = args.size();
    std::vector<po::option> result;
    for (auto const& parser : style_parsers) {
        auto const next = parser(args);
        result.insert(result.end(), next.begin(), next.end());
        if (args.size() != current_size)
            return result;
    }
    if (args.size() && args[0] != "--") args.insert(args.begin(), "--");
    auto const next = cmdline.parse_terminator(args);
    result.insert(result.end(), next.begin(), next.end());
    return result;
});
po::parsed_options parsed{&desc};
parsed.options = cmdline.run();
po::store(parsed, vm);
po::notify(vm);

Example警告:这是对未记录的库内部进行的黑客攻击,并且随时可能被破坏。

关于c++ - 使用 Boost.Program_options 创建前缀命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37996617/

相关文章:

c++ - 为什么 std::shared_ptr<void> 工作

c++ - boost::进程间消息队列抛出错误

c++ - 自 C++17 允许显式指定某些类模板参数以来,构造函数的模板参数推导是否可用?

c++ - 访问 C++ 父类的私有(private)成员

c++ - Mac 上的 Qt : boost filesystem library - symbols not found for architecture x86_64

c++ -std=c++0x 导致段错误( boost 日志记录)

java - 获取 Java 运行时参数 --argumentName=argumentValue

python - 为什么我需要 "sys.argv"才能在 PyQt 中启动 QApplication?

linux - 如何将可变参数与 wpa_passphrase 一起使用?

c++ - 警告 :"pointless comparison of unsigned integer with zero"cuda