更改 boost::program_options 中的元变量

Change the metavars in boost::program_options

这是一个纯粹的美学问题。 我用 C++ 编写了一个 CLI 程序并使用 boost::program_options 来传递它的参数。 默认情况下,boost 命名所有元变量 arg。我想改变它。

代码如下:

#include <iostream>
using std::cerr;
using std::cout;

#include <optional>
using std::optional;

#include <string>
using std::string;

#include <boost/program_options.hpp>
using boost::program_options::unknown_option;

#include "Net.h"

#include "GameServer.h"
using proto::GameServer;

namespace args = boost::program_options;

static auto parseArgs(int argc, const char *argv[])
{
    args::options_description desc("Command line options");
    desc.add_options()
        ("help,h", "Show this page")
        ("address,a", args::value<string>()->default_value(net::Defaults::HOST), "IP address to listen on")
        ("port,p", args::value<unsigned short>()->default_value(net::Defaults::PORT), "Port to listen on")
    ;

    optional<args::variables_map> result;
    args::variables_map varMap;

    try {
        args::store(args::parse_command_line(argc, argv, desc), varMap);
    } catch (unknown_option const &error) {
        cerr << "Invalid option: " << error.get_option_name() << "\n";
        cerr << desc << "\n";
        return result;
    }

    args::notify(varMap);

    if (varMap.count("help")) {
        cout << desc << "\n";
        return result;
    }

    return result = varMap;
}

int main(int argc, const char *argv[])
{
    auto parsedArgs = parseArgs(argc, argv);
    if (!parsedArgs.has_value())
        return 1;

    auto args = parsedArgs.value();
    auto address = args.at("address").as<string>();
    auto port = args.at("port").as<unsigned short>();

    GameServer server(address, port);
    server.listen();
}

帮助页面生成的输出:

Command line options:
  -h [ --help ]                     Show this page
  -a [ --address ] arg (=127.0.0.1) IP address to listen on
  -p [ --port ] arg (=9000)         Port to listen on

我想将 -aarg 重命名为 ip_address-pportnum 分别重命名。

似乎是 boost::program_options 的未记录部分,我快速查看了 boost::program_options 的实现,发现有一个 global variable 用于控制行为,所以我们提出了一行代码破解:

args::arg = "i_am_not_arg";

修改全局变量不是一个优雅的方式,但我还没有找到任何可用的API来做,你可以多研究并尝试找到更好的解决方案(别忘了在这里通知我! )

将此行插入代码的某个位置,然后我们得到 --help 命令行的输出:

->./a.out --help
Command line options:
  -h [ --help ]                         Show this page
  -a [ --address ] i_am_not_arg (=1234) IP address to listen on
  -p [ --port ] i_am_not_arg (=42)      Port to listen on

关于 SO 提问的建议:

  • 提供一个最小的、可复制的程序。您的代码无法在我的机器上编译,因为您使用了未提供的文件中的变量。

Online demo

@prehistoricpenguin 的回答让我走上了正轨。在 boost 中,typed_value class 有一个方法 value_name() 来设置参数名称,其工作方式类似于设置默认值,即它修改值对象并 returns 它为后续操作:

static auto parseArgs(int argc, const char *argv[])
{
    options_description desc("Command line options");
    desc.add_options()
            ("help,h", "Show this page")
            ("address,a", value<string>()->default_value(HOST)->value_name("ip_address"),
                    "IP address to connect to")
            ("port,p", value<unsigned short>()->default_value(PORT)->value_name("portnum"),
                    "Port to connect to");
    return parseArgDesc(argc, argv, desc);
}

导致:

Command line options:
  -h [ --help ]                         Show this page
  -a [ --address ] ip_address (=127.0.0.1)
                                        IP address to connect to
  -p [ --port ] portnum (=9000)         Port to connect to