c++boostcommand-line-interfacecommand-line-argumentsboost-program-options

What's the best way to pass an empty string as argument to boost::program_options?


I have a program that use boost::program_options to parse a command line. One of the parameter is the name of an AMQP exchange, and a default value is provided. For testing purposes, I would like to override this AMQP exchange name with an empty string (to use a default exchange).

I don't know how to pass an empty string to boost::program_options. Is that possible? Without modifying the source code? If not, what do you recommend?

Here is a minimum working example code :

#include <boost/program_options.hpp>

namespace po = boost::program_options;

constexpr auto EXECUTABLE_DESCRIPTION = 
"Minimum working example showing my difficulties while trying to " 
"pass an empty string as an argument to boost::program_options.";

int main(int argc, char **argv) {

  std::string elkExchange;
  po::options_description config("");
  config.add_options()
          ("amqp.exchange",
          po::value<std::string>(&elkExchange)  
          ->default_value("default-exchange"),  // default value used in prod
          "Exchange on which to send the events");

  // do the parsing 
  po::options_description cmdline_options(std::string{EXECUTABLE_DESCRIPTION});
  cmdline_options.add(config);
  po::variables_map args;
  store(po::command_line_parser(argc, argv).
          options(cmdline_options).run(), args);
  notify(args);

  // debug display 
  std::cout << "Send event on elk.exchange: {" << elkExchange << "}" << std::endl;

  // real application code here ...

  return EXIT_SUCCESS;
}

Here is what I would like to do:

# default value is used as expected
$ ./boost/empty-string-in-cli/exec
Send event on elk.exchange: {default-exchange}

# override with non-empty value work as expected
$ ./boost/empty-string-in-cli/exec --amqp.exchange='custom'
Send event on elk.exchange: {custom}

# here is where the troubles begin
$ ./boost/empty-string-in-cli/exec --amqp.exchange=''
terminate called after throwing an instance of 'boost::wrapexcept<boost::program_options::invalid_command_line_syntax>'
  what():  the argument for option '--amqp.exchange' should follow immediately after the equal sign
Aborted (core dumped)

Thanks in advance : )


Solution

  • To my surprise, the adjacent long option parser absolutely forbids the = sign with a zerolength value, see the code on https://github.com/boostorg/program_options/blob/develop/src/cmdline.cpp#L520.

    Therefore it seems your only recourse is to avoid using the adjacent-value syntax:

    for EXCHANGE in foo bar ''; do ./build/sotest --amqp.exchange "$EXCHANGE"; done
    

    Prints

    Send event on elk.exchange: {foo}
    Send event on elk.exchange: {bar}
    Send event on elk.exchange: {}