This is a C++ implementation of Python's argparse
module. The aim is to cover as much functionality as possible and retain argparse
's familiarity and ease of use. Everyone who already used Python should feel at home using this library. At the same time, the library is implemented using modern C++ features.
C++ argparse is a header-only library, so its setup is minimal. It has no external dependencies and only uses STL. Since it uses std::ranges
and some other features, it requires C++20 compiler and standard library. If your compiler struggles, you can switch to v2.2.0, or if you are stuck with C++17, you can still use release v2.1.4.
C++ argparse uses CMake internally, but you don't have to. Just put the argparse.h header somewhere and point your build system to it.
Unit tests use doctest unit testing framework.
This library strives to provide Python-like arguments parsing experience for C++ developers. However, where Python and C++ clash, this implementation goes the C++ way using its idioms.
One obvious example is the lack of C++ support for named function parameters. While in Python you can do
parser = argparse.ArgumentParser(prog='app', usage='%(prog)s', description='Showcase app')
in C++ you need something else. C++ argparse uses Named Parameter Idiom to achieve similar functionality:
auto parser = argparse::ArgumentParser().prog("app").usage("%(prog)s").description("Showcase app");
It is a bit more verbose and a bit less convenient, but I believe it is still usable.
The parse_args()
function adds attributes representing parsed arguments to an instance of a Namespace
class at runtime. In Python creating custom types at runtime is not a problem. Not so in C++. Instead of returning a bespoke class instance, C++ argparse returns a mapping object that uses argument names as keys. This is not as convenient, but not too bad either.
Python does not have any static type-safety built in and instead depends on runtime checks. Therefore it is fine to pass some things as strings:
parser.add_argument('--option', action='store_true')
In C++ we can ask the compiler to help us detect bugs at compile-time, and this is what C++ argparse does. Instead of passing actions as strings, we use enum
s here:
parser.add_argument("--option").action(argparse::store_true);
If you make a typo, your compiler will let you know.
Python is a dynamically typed language while C++ is statically typed. This means that while in Python a function can return any type
def fun(arg):
if not arg:
return None
elif arg == 10:
return 'ten'
else:
return 42
in C++ we need a workaround. The workaroud used here is template-based. To get a parsed value, you need to specify which type you expect:
auto args = parser.parse_args(argc, argv);
auto force = args.get_value<bool>("force");
The only exception is std::string
which is returned by default by the non-template function overload:
auto args = parser.parse_args(argc, argv);
auto file_name = args.get_value("filename");
You can follow the tutorial in the project's tutorial
subdirectory to learn how to use this library. A short example follows below:
#include "argparse.h"
int move_file(std::string const & src, std::string const & dst, bool force, bool verbose);
int main(int argc, char* argv[])
{
auto parser = argparse::ArgumentParser();
parser.add_argument("source").help("source file path");
parser.add_argument("destination").help("destination file path");
parser.add_argument("-f", "--force").help("force copying").action(argparse::store_true);
parser.add_argument("-v", "--verbose").help("prints additional information").action(argparse::store_true);
auto args = parser.parse_args(argc, argv);
auto result = move_file(args.get_value("source"), args.get_value("destination"), args.get_value<bool>("force"), args.get_value<bool>("verbose"));
return result;
}
The below lists features of the argparse
module that this implementation supports:
-
ArgumentParser
objects-
prog
-
usage
-
description
-
epilog
-
parents
-
formatter_class
-
prefix_chars
-
fromfile_prefix_chars
-
argument_default
-
allow_abbrev
-
conflict_handler
-
add_help
-
-
The
add_argument()
method- name or flags
-
action
(onlystore
,store_true
,store_false
,store_const
, andhelp
) -
nargs
(except forREMAINDER
) -
const
(renamed toconst_
due to keyword clash) -
default
(renamed todefault_
due to keyword clash; only for optional arguments and with no string parsing) -
type
(built-in (except forbool
) and user-defined types (via overloadingfrom_string
function)) -
choices
-
required
-
help
-
metavar
(only for single nargs) -
dest
-
The
parse_args()
method- no defaults, you need to pass
argc
andargv
explicitly (normally, forward what you got inmain
) - option value syntax
- passing long option and value as a single command-line argument (
--foo=FOO
) - passing short option and value concatenated (
-xX
) - joining together several short options (
-xyz
) - double-dash pseudo-argument (
--
) - argument abbreviations (prefix matching)
- passing long option and value as a single command-line argument (
- no defaults, you need to pass
-
Mutual exclusion
- you can put optional arguments in a mutually exclusive group to have only one of them accepted by the parser
- the group itself (together with its arguments) is optional
This project is released under MIT license, so feel free to do anything you like with it.