如何使用boost :: program_options创建选项别名?

时间:2017-02-06 10:23:03

标签: c++ c++11 boost boost-program-options

我希望能够创建boost::program_options的选项别名,将其参数存储在相同的键/标签下。

我的软件架构使用不同的专用选项解析器,具体取决于值argv[1]。但是,有些选项是共享的,例如我的选项--inputs

inputOptions.add_options()
        ("--inputs",
         po::value< std::vector<std::string> >()->value_name("paths"),
         "List of files to edit.\n");

为了与旧版本的程序兼容,我想在其中一个子解析器中添加一个兼容性选项--input,将其参数存储在“--inputs”下。理想情况下,该选项最多只能使用一个参数而不是任意多个参数。但是,如果您提供的解决方案使--input--inputs相同,我想也没关系,因为在这种情况下,位置选项仍会发送到“--inputs”。

感谢您的帮助!

3 个答案:

答案 0 :(得分:3)

您可以使用extra_parser(请参阅文档中的Non-conventional syntax),即解析器,可用于在进一步处理令牌之前操纵来自输入的令牌。它可以用于将--run转换为--command=run等之类的事情。

Extra解析器是具有以下签名的函子:

std::pair<std::string, std::string>(const std::string &s)

它应该在pair::first中返回选项名称,并在pair::second中返回(可选)选项值。 pair::first为空表示多余的解析器未解析任何内容。值(即pair::second)可以为空-仅解析了选项名称。如果返回的对有效,则使用名称或名称/值对,而不是通过常规机制来解析原始令牌。

首先,我们编写别名函数:

using OptionAliases = std::map<std::string, std::string>;

std::pair<std::string, std::string>
renameOptions(const std::string &token, const OptionAliases &aliases)
{
    auto rtoken(boost::make_iterator_range(token));

    // consume "--" prefix
    if (!boost::algorithm::starts_with(rtoken, "--")) { return { "", "" }; }
    rtoken.advance_begin(2);

    // find equal sign (returns iterator range)
    const auto eq(boost::algorithm::find_first(rtoken, "="));

    // extract option (between "--prefix" and "="/end()) and map it to output
    const auto faliases(aliases.find(std::string(rtoken.begin(), eq.begin())));
    if (faliases == aliases.end()) { return { "", "" }; }

    // return remapped option and (optionally) value after "="
    return std::make_pair(faliases->second
                          , std::string(eq.end(), rtoken.end()));
}

它只是将输入令牌分为--name=value(如果没有=符号则没有值)和名称在提供的别名映射中找到它会返回(remapped-name, value)

然后,我们使用lambda创建解析器本身:

boost::program_options::ext_parser optionAlias(OptionAliases &&aliases)
{
    return [aliases{std::move(aliases)}](const std::string &token)
    {
        return renameOptions(token, aliases);
    };
}

((至少需要C ++ 14,C ++ 11更改为return [aliases](con...

您可以将此解析器插入cmdline解析器:

parser.extra_parser(optionAlias({{"mark.twain", "samuel.clemens"}
                                  , {"lewis.caroll", "charles.dodgson"}}));

现在,在上面的示例中,--mark.twain--samuel.clemens都指向vars["samuel.clemens"],而--lewis.caroll--charles.dodgson都指向{{1} }。

注意事项

  • 仅适用于命令行解析器。
  • 期望vars["charles.dodgson"]样式(前缀为allow_long的长选项)。可以在代码中更改。
  • 期望--样式(使用long_allow_adjacent在一个令牌中允许的值)。也可以在代码中更改。
  • 如果有任何非选项令牌都解析为=,则由于没有上下文,它也将被转换。无法绕开。

    示例:如果有一个名称为--alias的选项期望值并且使用了name样式,则long_allow_next将被解析为选项--name=--mark.twain,其值为{{1 }}(按预期方式),而name将被解析为选项--mark.twain,其值为--name --mark.twain

    简短地说,它可以按预期工作。

希望有帮助。

答案 1 :(得分:2)

您是否尝试过使用po::value<...>(&variable)表单?解析后,该选项的值将直接保存到变量中。然后,您可以添加指向同一变量的两个选项--input--inputs。此外,您可能必须检查是否只使用了两个选项中的一个,否则会显示错误消息。

我希望我能正确理解你的问题。

答案 2 :(得分:0)

默认情况下,boost :: program_options允许长选项的前缀与该选项匹配。因此,您编写的代码将已经接受--input作为--inputs的别名。