Search code examples
c++boostc++17command-line-arguments

Change the metavars in boost::program_options


This is a purely aesthetic issue. I have written a CLI program in C++ and use boost::program_options to pasrse its args. Per default, boost names all meta variables arg. I'd like to change that.

Here's the code:

#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();
}

And the output generated by the help page:

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

I'd like to rename arg for -a to ip_address and for -p to portnum respectively.


Solution

  • @prehistoricpenguin's answer brought me onto the right track. In boost, the typed_value class has a method value_name() to set the argument name, which works analogous to setting the defaults, i.e. it modifies the value object and returns it for subsequent operations:

    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);
    }
    

    Resulting in:

    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