C++ Argument Parser (like python argparse)
- Requirement
- A Simple Example
- ArgumentParser
- Argument
- The parse_args() method
- Sub-commands
- Argument Groups
- Mutually Exclusive Groups
- C++17
Here's a simple example.
#include <iostream>
#include <argparse/argparse.h>
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser();
parser.add_argument("square")
.set_help("display a square of a given number");
parser.add_argument("-v", "--verbose", argparse::actions::StoreTrueAction())
.set_help("increase output verbosity");
auto args = parser.parse_args(argc, argv);
int square = args.get<int>("square");
if (args.get<bool>("verbose")) {
std::cout << "the square of " << square << " equals " << square * square << std::endl;
}
else {
std::cout << square * square << std::endl;
}
return 0;
}
Running this code after compiling:
$ ./program 4
16
$ ./program 4 --verbose
the square of 4 equals 16
$ ./program --verbose 4
the square of 4 equals 16
$ ./program -h
usage: program [-h] [-v] square
positional arguments:
square display a square of a given number
options:
-h, --help show this help message and exit
-v, --verbose increase output verbosity
- The
add_argument(...)
method ofArgumentParser
adds command-line options the program will receive: The argumentsquare
is a positional argument and the argument-v
(--version
) is an optional argument. - The
add_argument(...)
returns a reference to the addedArgument
object. The returned reference allows for the setting of various argument's properties. - The
parse_args(argc, argv)
method enables reading command-line arguments and returns a map object(Namespace
) that stores the given arguments and their values as key-value pairs. - All argument values are stored as strings. The stored values can be accessed through the
get<T>("key")
method of the returned map object.
namespace argparse {
class ArgumentParser(std::string_view const prog_name = "", bool const help = true, char const prefix_char = '-', bool const exit_on_error_ = true)
}
prog_name
- The name of the program (default: the first command-line argument)help
- Add a-h/--help
option to the parser (default:true
)prefix_char
- The character that prefix optional arguments (default:-
)exit_on_error
- Determines whether or not ArgumentParser exits with error info when an error occurs (default:true
)
By default, ArgumentParser
object use the first command-line argument to determine how to display the name of the program in help messages. Default value is set when parsing command-line arguments. For example, consider a executable named program
with the following code:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser();
parser.add_argument("--foo").set_help("foo help");
auto args = parser.parse_args(argc, argv);
}
The help for this program will display program
as the program name (regardless of where the program was invoked from):
$ ./program --help
usage: program [-h] [--foo FOO]
options:
-h, --help show this help message and exit
--foo FOO foo help
To change this default behavior, another value can be suppplied using the prog_name
argument to ArgumentParser
:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("myprogram");
parser.add_argument("--foo").set_help("foo help");
auto args = parser.parse_args(argc, argv);
}
$ ./program --help
usage: myprogram [-h] [--foo FOO]
options:
-h, --help show this help message and exit
--foo FOO foo help
By default, ArgumentParser
objects add an option which simple displays the parser's help message. For example, consider a file named program
containing the following code:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser();
parser.add_argument("--foo").set_help("foo help");
auto args = parser.parse_args(argc, argv);
}
If -h
or --help
is supplied at the command line, the ArgumentParser
help will be printed:
$ ./program --help
usage: program [-h] [--foo FOO]
options:
-h, --help show this help message and exit
--foo FOO foo help
Occasionally, it may be usefule to disable the addition of this help option. This can be achieved by passing false
as the help
argument to the ArgumentParser
constructor:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program", false);
parser.add_argument("--foo").set_help("foo help");
parser.print_help();
}
$ ./program
usage: program [--foo FOO]
options:
--foo FOO foo help
The help option is typically -h/--help
. The execption to this is if the prefix_char
is specified to another character, in which case -h
and --help
are not valid options.
refer to 02_help_argument.cpp
Most command-line options will use -
as the prefix, e.g. -f/--foo
. Parsers that need to support different or additional prefix characters, e.g. for options like +f
or /foo
, may specify them using the prefix_char
argument to the ArgumentParser
constructor:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program", true, '+');
parser.add_argument("+f");
parser.add_argument("++bar");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program +f X ++bar Y
Namespace(bar=Y, f=X)
Normally, when you pass an invalid argument list to the parse_args(...)
method of an ArgumentParser
, it will exit with error info.
If the user would like to catch errors manually, the feature can be enabled by setting exit_on_error
argument to false
:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program", true, '-', false);
parser.add_argument("--foo");
try {
auto args = parser.parse_args(argc, argv);
}
catch (std::exception& e) {
std::cout << "catch exception\n";
std::cout << e.what() << std::endl;
}
}
$ ./program --foo
catch exception
argument --foo: expected one argument
refer to 03_exit_on_error.cpp
Normally, when you pass an argument list to the parse_args()
method of an ArgumentParser
, it recognizes abbreviations of long options.
This feature can be disabled by calling set_abbrev()
with false
.
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.set_abbrev(false);
parser.add_argument("--foobar", argparse::actions::StoreTrueAction());
parser.add_argument("--foonley", argparse::actions::StoreFalseAction());
auto args = parser.parse_args(argc, argv);
}
$ ./program --foon
usage: program [-h] [--foobar] [--foonley]
[ARGPARSE ERROR] unrecognized arguments: --foon
refer to 01_allow_abbrev.cpp
namespace argparse {
template<typename... Args>
Argument& ArgumentParser::add_argument(Args&&... args);
}
To add a new argument (Argument
), call the add_argument(...)
method. This method must know whether an optional argument, or a positional argument is expected. The arguments passed to add_argument()
must therefore be either a series of flags, or a simple argument name.
For example, an optional argument could be created like:
parser.add_argument("-f", "--foo");
while a positional argument could be created like:
parser.add_argument("bar");
When parse_args()
is called, optional arguments will be identified by the -
prefix, and the remaining arguments will be assumed to be positional:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("-f", "--foo");
parser.add_argument("bar");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program BAR
Namespace(bar=BAR)
$ ./program BAR --foo FOO
Namespace(foo=FOO, bar=BAR)
$ ./program --foo FOO
usage: program [-h] [-f FOO] bar
[ARGPARSE ERROR] the following arguments are required: bar
Argument
objects is associated with actions. These actions can do just about anything with the command-line arguments associated with them, though most actions simple add an attirbute to the object returned by parse_args()
. The action specifies how the command-line arguments should be handled. An action can be set by passing the Action
class as the last argument to the add_argument()
method. The supplied actions are:
StoreAction
- This just stores the argument's value. This is the default action.StoreConstAction
- This stores the specified value byset_const()
method. Default const value is empty. TheStoreConstAction
action is most commonly used with optional arguments that specify some sort of flag.StoreTrueAction
andStoreFalseAction
- These are special cases ofStoreConstAction
used for storing the valuestrue
andfalse
respectively. In addition, they create default values offalse
andtrue
respectively.AppendAction
- This stores a list, and appends each argument value to the list. It is useful to allow an option to be specified multiple times. If the default value is non-empty, the default elements will be present in the parsed value for the option, with any values from the command line appended after those default values.AppendConstAction
- This stores a list, and appends the value specified by theset_const
method to the list.AppendConstAction
is typically useful when multiple arguments need to store constants to the same list.CountAction
- This counts the number of times a keyword argument occurs. This is useful for increasing verbosity levels.HelpAction
- This prints a complete help message for all the options in the current parser and then exits. By default a help action is automatically added to the parser.
If you need an action other than the above actions, you can define and use a custom action. A custom action requires 3 methods - initialize()
, get_action()
, get_valid()
:
class FooAction
{
public:
void initialize(argparse::Argument& argument) {
// do nothing
}
argparse::Action get_action() {
return [](argparse::ArgumentParser* parser, argparse::Namespace& ret, argparse::Argument const& argument, std::vector<std::string> const& values) {
std::cout << ret << ' ' << argument.get_dest() << " = " << values[0] << std::endl;
ret[argument.get_dest()] = values;
};
}
argparse::Validation get_valid() {
return [](argparse::Argument const& argument) {
if (argument.get_nargs().get_type() != argparse::NArgs::Type::none) {
throw std::invalid_argument("nargs not allowed");
}
};
}
};
for examples, refer to 05_actions.cpp and 06_custom_action.cpp
Argument
objects usually associate a single command-line argument with a single action to be taken. The nargs
associates a different number of command-line arguments with a single action. The nargs
can be set by set_nargs()
method. The supported values are:
N
(an integer) -N
arguments from the command line will be gathered together into a list.?
(optional) - One argument will be consumed from the command line if possible, and produced as a single item. If no command-line argument is present, the value that is set byset_default
method will be produced.
Note that for optional arguments, there is an additional case - the option string is present but not followed by a command-line argument. In this case the value fromconst
will be produced.*
(zero or more) - All command-line arguments present are gathered into a list.
Note that it generally doesn't make much sense to have more than one positional argument withnargs='*'
, but multiple optional arguments withnargs='*'
is possible.+
(one or more) - Just like*
, all command-line arguments present are gathered into a list. Additionally, an error message will be gathered if there wasn't one command-line argument present.
If the nargs
is not set from set_nargs
method, the number of arguments consumed is determined by the action
. Generally this means a single command-line argument will be consumed and a single item will be produced.
refer to 07_nargs.cpp
The const_value
of Argument
is used to hold constant values that are not read from the command line but are required for the various actions. The const_value
can be set by calling set_const()
. The two most common uses of it are:
- When
add_argument()
is called withStoreConstAction()
orAppendConstAction()
. These actions add theconst_value
to one of the attirbutes of the object returned byparse_args()
. See 05_actions.cpp for examples. Ifconst_value
is not set fromset_const()
, it will receive no values (a default value in the object returned byparse_args()
is initialized toNone
). - When
add_argument()
is called with option strings (like-f
or--foo
) andnargs='?'
. This creates an optional argument that can be followed by zero or one command-line arguments.
All optional arguments and some positional arguments may be omitted at the command line. The default_value
of Argument
specifies what value should be used if the command-line argument is not present. The default_value
can be set by calling set_default()
. For optional arguments, the default_value
is used when the option string was not present at the command line:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("--foo")
.set_default(42); // or passing "42"
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program --foo 2
Namespace(foo=2)
$ ./program
Namespace(foo=42)
For positional arguments with nargs
equal to ?
or *
, the default_value
is used when no command-line argument was present:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("foo")
.set_nargs('?')
.set_default(42);
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program a
Namespace(foo=a)
$ ./program
Namespace(foo=42)
Passing argparse::Argument::SUPPRESS
to set_default()
causes no attribute to be added if the command-line argument was not present:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("--foo")
.set_default(argparse::Argument::SUPPRESS);
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program
Namespace()
$ ./program --foo 1
Namespace(foo=1)
Some command-line arguments should be selected from a restricted set of values. These can be handled by passing a sequence of strings as argument to set_choices()
method. When the command line is paresed, argument values will be checked, and an error message will be displayed if the argument was not one of the acceptable values:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("move")
.set_choices({"rock", "paper", "scissors"});
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program rock
Namespace(move=rock)
$ ./program fire
usage: program [-h] {rock,paper,scissors}
[ARGPARSE ERROR] argument move: invalid choice: 'fire' (choose from 'rock', 'paper', 'scissors')
refer to 08_choices.cpp
In general, the ArgumentParser
assumes that flags like -f
and --bar
indicate optional arguments, which can always be omitted at the command line. To make an option required, true
can be specified by calling set_required()
:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("--foo")
.set_required(true);
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program --foo BAR
Namespace(foo=BAR)
$ ./program
usage: program [-h] --foo FOO
[ARGPARSE ERROR] the following arguments are required: --foo
As the example shows, if an option is marked as required
, parse_args()
will report an error if that option is not present at the command line.
The help
is a string containing a brief description of the argument. When a user requests help (usually by using -h
or --help
at the command line), these help
description will be displayed with each argument. The help
description can be set by set_help()
method:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("frobble");
parser.add_argument("--foo", argparse::actions::StoreTrueAction())
.set_help("foo the bars before frobbling");
parser.add_argument("bar")
.set_nargs('+')
.set_help("one of the bars to be frobbled");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./frobble -h
usage: frobble [-h] [--foo] bar [bar ...]
positional arguments:
bar one of the bars to be frobbled
options:
-h, --help show this help message and exit
--foo foo the bars before frobbling
ArgumentParser
supports silencing the help entry for certain options, by setting the help
to argparse::Argument::SUPPRESS
:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("frobble");
parser.add_argument("--foo", argparse::actions::StoreTrueAction())
.set_help(argparse::Argument::SUPPRESS);
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./frobble -h
usage: frobble [-h]
options:
-h, --help show this help message and exit
When ArgumentParser
generates help messages, it needs some way to refer to each expected argument. By default, ArgumentParser
objects use the dest
value as the "name" of each object. By default, for positional arguments, the dest
value is used directly, and for optional arguments, the dest
value is uppercased. So, a single positional argument with dest="bar"
will be referred to as bar
. A single optional argument --foo
that should be followed by a single command-line argument will be referred to as FOO
. An example:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("--foo")
.set_metavar("YYY");
parser.add_argument("bar")
.set_metavar("XXX");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program X --foo Y
Namespace(foo=Y, bar=X)
$ ./program -h
usage: program [-h] [--foo YYY] XXX
positional arguments:
XXX
options:
-h, --help show this help message and exit
--foo YYY
Note that metavar
only changes the displayed name - the name of the attribute on the object returned by parse_args()
is still determined by the dest
value.
Not supported that different values of
nargs
cause themetavar
to be used multiple times.
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("x")
.set_nargs(2);
parser.add_argument("--foo")
.set_nargs(2)
.set_metavar("bar");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program -h
usage: program [-h] [--foo bar bar] x x
positional arguments:
x
options:
-h, --help show this help message and exit
--foo bar bar
Most actions add some value as an attribute of the object returned by parse_args()
. The name of this attribute is determined by the dest
value of Argument
. For positional arguments, dest
is normally supplied as the first argument to add_argument()
:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("bar");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program XXX
Namespace(bar=XXX)
For optional arguments, the value of dest
is normally inferred from the option strings. ArgumentParser
generates the value of dest
by taking the first long option string and stripping away the initial --
string. If no long option strings were supplied, dest
will be derived from the first short option string by stripping the initial -
character. Any internal -
characters will be converted to _
characters to make sure the string is a valid attribute name. The example below illustrate this behavior:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("-f", "--foo-bar", "--foo");
parser.add_argument("-x", "-y");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program -f 1 -x 2
Namespace(x=2, foo_bar=1)
$ ./program --foo 1 -y 2
Namespace(x=2, foo_bar=1)
dest
allows a custom attribute name by calling set_dest()
method:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("--foo")
.set_dest("bar");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program --foo XXX
Namespace(bar=XXX)
namespace argparse {
Namespace ArgumentParser::parse_args(int argc, char const *const *const argv);
}
parse_args()
converts argument strings to objects and assign them as attributes of the returned object (Namespace
object).
The parse_args()
method supports several ways of specifying the value of an option (if it takes one). In the simplest case, the option and its value are passed as two separate arguments:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("-x");
parser.add_argument("--foo");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program -x X
Namespace(x=X)
$ ./program --foo FOO
Namespace(foo=FOO)
The option and value can also be passed as a single command-line argument, using =
to separate them:
$ ./program --foo=FOO -x=X
Namespace(foo=FOO, x=X)
For short options (options only one character long), the option and its value can be concatenated:
$ ./program -xX
Namespace(x=X)
Several short options can be joined together, using only a single -
prefix, as long as only the last option (or none of them) requires a value:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("-x", argparse::actions::StoreTrueAction());
parser.add_argument("-y", argparse::actions::StoreTrueAction());
parser.add_argument("-z");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program -xyzZ
Namespace(z=Z, y=true, x=true)
While parsing the command line, parse_args()
checks for a variety of errors, including ambigous options, invalid options, wrong number of positional arguments, etc. When it encounters such an error, it exits and prints the error along with a usage message:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("--foo");
parser.add_argument("bar")
.set_nargs('?');
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
# invalid option
$ ./program --bar
usage: program [-h] [--foo FOO] [bar]
[ARGPARSE ERROR] unrecognized arguments: --bar
# wrong number of arguments
$ ./program spam badger
usage: program [-h] [--foo FOO] [bar]
[ARGPARSE ERROR] unrecognized arguments: badger
The parse_args()
method attempts to give errors whenever the user has clearly made a mistake, but some situations are inherently ambigous. For example, the command-line argument -1
could either be an attemp to specify an option or an attemp to provide a positional argument. The parse_args()
method is cautious here: positional arguments may only begin with -
if they look like negative numbers and there are no options in the parser that look like negative numbers:
Ex1:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("-x");
parser.add_argument("foo")
.set_nargs('?');
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
# no negative number options, so -1 is a positional argument
$ ./program -x -1
Namespace(x=-1)
# no negative number options, so -1 and -5 are positional arguments
$ ./program -x -1 -5
Namespace(foo=-5, x=-1)
Ex2:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("-1")
.set_dest("one");
parser.add_argument("foo")
.set_nargs('?');
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
# negative number options present, so -1 is an option
$ ./program -1 X
Namespace(one=X)
# negative number options present, so -2 is an option
$ ./program -2
usage: program [-h] [-1 ONE] [foo]
[ARGPARSE ERROR] unrecognized arguments: -2
# negative number options present, so both -1s are options
$ ./program -1 -1
usage: program [-h] [-1 ONE] [foo]
[ARGPARSE ERROR] argument -1: expected one argument
If you have positional arguments that must begin with -
and don't look like negative numbers, you can insert the pseudo-argument --
which tells parse_args()
that everything after that is a positonal argument:
$ ./program -- -f
Namespace(foo=-f)
The parse_args()
method by default allows long options to be abbreviated to a prefix, if the abbreviation is unambiguous (the prefix matches a unique option):
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
parser.add_argument("-bacon");
parser.add_argument("-badger");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program -bac MMM
Namespace(bacon=MMM)
$ ./program -bad WOOD
Namespace(badger=WOOD)
$ ./program -ba BA
usage: program [-h] [-bacon BACON] [-badger BADGER]
[ARGPARSE ERROR] ambiguous option: -ba could match -bacon, -badger
An error is produced for arguments that could produce more than one options. This feature can be disabled by setting allow_abbrev
to false
.
namespace argparse {
class Namespace;
}
This class is deliberately simple for storing values on the attributes. Internally, the values are stored as strings in the map
object. You can get the value stored in Namespace
object by the parser using get<T>(key)
method of Namespace
object.
If you want to check whether the key-value exists before reading the value, you can call has(key)
method which returns boolean value.
auto args = parser.parse_args(argc, argv);
int foo_value = args.get<int>("foo");
bool bar_value = args.get<bool>("bar");
if (args.has("foo_bar")) {
std::vector<int> value_list = args.get<std::vector<int>>("foo_bar");
}
Beyond
Namespace
:
All values are stored as a sequence of strings. If you specify template parameter as a single type likeget<int>(key)
, which returns the first value in the sequence of strings as specified type. If the desired return type is not a string, additional conversion is performed internally. When a container type is passed the template parameter likeget<std::vector<int>>(key)
orget<std::list<float>>(key)
, it returns a sequence of values as desired container type.
Many programs split up their functionality into a number of sub-commands, for example, the git
program cna invoke sub-commands like git checkout
, git clone
, and git commit
. Splitting up functionality this way can be a particularly good idea when a program performs several different functions which require different kinds of command-line arguments. ArgumentParser
supports the creation of such sub-commands with the add_subparsers()
method. The add_subparsers()
method is normally called with no arguments and returns a Argument
object with special action. This object can call a additional method, add_parser()
, which takes a command name and so on, and returns an ArgumentParser
object that can be modified as usual.
Note: Currently,
ArgumentParser
constructor arguments are not supported when callingadd_parser()
.
namespace argparse {
Argument& ArgumentParser::add_subparsers(std::string_view title = "", std::string_view description = "");
ArgumentParser& Argument::add_parser(std::string const& name, std::vector<std::string> const& aliases, std::string_view help);
}
Description of parameters
For add_subparsers()
:
title
- title for the sub-parser group in help output: by default "subcommands" if description is provided, otherwise uses title for positional argumentsdescription
- description for the sub-parser group in help output
For add_parser()
:
name
- command of the subparser likecheckout
ofgit
programaliases
- aliases of the subcommandhelp
- help message for the subparser command
Example usage:
int main(int argc, char** argv) {
// create the top-level parser
auto parser = argparse::ArgumentParser("program");
parser.add_argument("--foo", argparse::actions::StoreTrueAction())
.set_help("foo help");
auto& subparsers = parser.add_subparsers();
subparsers.set_help("sub-command help");
// create the parser for the 'a' command
auto& parser_a = subparsers.add_parser("a", {}, "a help");
parser_a.add_argument("bar").set_help("bar help");
// create the parser for the 'b' command
auto& parser_b = subparsers.add_parser("b", {}, "b help");
parser_b.add_argument("--baz").set_choices({"X", "Y", "Z"}).set_help("baz help");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program a 12
Namespace(bar=12, foo=false)
$ ./program --foo b --baz Z
Namespace(baz=Z, foo=true)
Note that the object returned by parse_args()
will only contain attributes for the main parser and the subparer that was selected by the command line (and not any other subparsers). So in the example above, when the a
command is specified, only the foo
and bar
attributes are present, and when the b
command is specified, only the foo
and baz
attributes are present.
Similarly, when a help message is requested from a subparser, only the help for that particular parser will be printed. The help message will not include parent parser or sibling parser messages. (A help message for each subparser command, however, can be given by calling set_help()
as above.)
$ ./program --help
usage: program [-h] [--foo] {a,b} ...
positional arguments:
{a,b} sub-command help
a a help
b b help
options:
-h, --help show this help message and exit
--foo foo help
$ ./program a --help
usage: program a [-h] bar
positional arguments:
bar bar help
options:
-h, --help show this help message and exit
$ ./program b --help
usage: program b [-h] [--baz {X,Y,Z}]
options:
-h, --help show this help message and exit
--baz {X,Y,Z} baz help
The add_subparsers()
method also supports title
and description
arguments. When either is present, the subparser's commands will appear in their own group in the help output. For example:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
auto& subparser = parser.add_subparsers("subcommands", "valid subcommands");
subparser.set_help("additional help");
subparser.add_parser("foo");
subparser.add_parser("bar");
auto args = parser.parse_args(argc, argv);
}
$ ./program -h
usage: program [-h] {foo,bar} ...
options:
-h, --help show this help message and exit
subcommands:
valid subcommands
{foo,bar} additional help
Furthermore, add_parser()
supports an additional aliases
argument, which allows multiple strings to refer to the same subparser. This example, aliases co
as a shorthand for checkout
:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
auto& subparser = parser.add_subparsers();
auto& checkout = subparser.add_parser("chekcout", {"co"});
checkout.add_argument("foo");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program co bar
Namespace(foo=bar)
If it is necessary to check the name of the subparser that was invoked, the dest
of subparser will work:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
auto& subparser = parser.add_subparsers();
subparser.set_dest("subparser_name");
auto& subparser1 = subparser.add_parser("1");
subparser1.add_argument("-x");
auto& subparser2 = subparser.add_parser("2");
subparser2.add_argument("y");
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program 2 frobble
Namespace(y=frobble, subparser_name=2)
namespace argparse {
ArgumentGroup& ArgumentParser::add_argument_group(std::string_view title, std::string_view description);
}
By default, ArgumentParser
groups command-line arguments into 'positional arguments' and 'options' when displaying help messages. When there is a better conceptual grouping of arguments than this default one, appropriate groups can be created using the add_argument_group()
method:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program", false);
auto& group = parser.add_argument_group("group");
group.add_argument("--foo").set_help("foo help");
group.add_argument("bar").set_help("bar help");
parser.print_help();
}
$ ./program
usage: program [--foo FOO] bar
group:
--foo FOO foo help
bar bar help
The add_argument_group()
method returns an argument group object which has an add_argument()
method just like a regular ArgumentParser
. When an argument is added to the group, the parser treats is just like a normal argument, but displays the argument in a separate group for help messages. The add_argument_group()
method accepts title
and description
arguments which can be used to customize this display:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program", false);
auto& group1 = parser.add_argument_group("group1", "group1 description");
group1.add_argument("foo").set_help("foo help");
auto& group2 = parser.add_argument_group("group2", "group2 description");
group2.add_argument("--bar").set_help("bar help");
parser.print_help();
}
$ ./program
usage: program [--bar BAR] foo
group1:
group1 description
foo foo help
group2:
group2 description
--bar BAR bar help
Note that any arguments not in your user-defined groups will end up back in the usual 'positional arguments' and 'options' sections.
namespace argparse {
MutuallyExclusiveGroup& ArgumentParser::add_mutually_exclusive_group(bool const required);
}
Create a mutually exclusive group. It will make sure that only one of the arguments in the mutually exclusive group was present on the command line.
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
auto& group = parser.add_mutually_exclusive_group();
group.add_argument("--foo", argparse::actions::StoreTrueAction());
group.add_argument("--bar", argparse::actions::StoreFalseAction());
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program --foo
Namespace(bar=true, foo=true)
$ ./program --bar
Namespace(bar=false, foo=false)
$ ./program --foo --bar
[ARGPARSE ERROR] argument --bar: not allowed with argument --foo
The add_mutually_exclusive_group()
method also accepts a required
argument, to indicate that at least one of the mutually exclusive is required:
int main(int argc, char** argv) {
auto parser = argparse::ArgumentParser("program");
auto& group = parser.add_mutually_exclusive_group(true);
group.add_argument("--foo", argparse::actions::StoreTrueAction());
group.add_argument("--bar", argparse::actions::StoreFalseAction());
auto args = parser.parse_args(argc, argv);
std::cout << args << std::endl;
}
$ ./program
[ARGPARSE ERROR] one of the arguments --foo --bar is required
Note: Some functionality needs to be updated.