I am writing a program that expects 2 required positional args. First argument has a limited set of string values. Second argument can be any string without restrictions. Program is meant to use second arg in different ways depending on selected action in first argument. For argument parsing, I use argparse/3.0.
The program that I wrote:
#include <iostream>
#include <stdexcept>
#include <argparse/argparse.hpp>
int main(int argc, char* argv[]) {
argparse::ArgumentParser program("my_program");
program.add_argument("mode")
.nargs(1)
.help("Mode of operation: option1 or option2")
.required()
.choices("option1", "option2");
program.add_argument("mode_arg")
.required()
.nargs(1)
.help("Any string");
try {
program.parse_args(argc, argv);
} catch (const std::runtime_error& e) {
std::cerr << e.what() << 'n';
std::cerr << program;
exit(1);
}
std::string mode = program.get<std::string>("mode");
std::string mode_arg = program.get<std::string>("mode_arg");
std::cout << "Mode: " << mode << std::endl;
std::cout << "Mode arg: " << mode_arg << std::endl;
return 0;
}
How I used it:
./main option1 value1
Invalid argument "value1" - allowed options: {option1, option2}
Usage: my_program [--help] [--version] mode mode_arg
Positional arguments:
mode Mode of operation: option1 or option2 [required]
mode_arg Any string [required]
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
I was expecting only option1
to be checked against allowed options*, because I specified .nargs(1)
while adding the argument. I can’t quite understand why both of supplied values are treated asmode
‘s arguments. I tried using different values for nargs
, but nothing seemed to work as expected.
*I can make it work as expected providing a lambda object as an action
s argument, like following:
program.add_argument("mode")
.nargs(1)
.help("Mode of operation: option1 or option2")
.required()
.action([](const std::string& value) {
if(value != "option1" && value != "option2") {
throw std::runtime_error("Wrong value.");
}
return value;
});
However I wanted to use .choices
method, since it surely is more elegant. Is my understanding of choices
method flawed?
What am I missing? How to provide (if possible at all) this functionality with .choices
method?