-
Notifications
You must be signed in to change notification settings - Fork 0
Examples
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser("Program name").SetDescription("Description of program");
parser.AddArgument(argparse::CreateNamedArgument()
.SetLongName("numbers")
.SetAnyNumberOfArgumentsButAtleastOne()
.SetType(argparse::ArgTypeCast::e_int));
parser.AddArgument(argparse::CreateNamedArgument()
.SetLongName("some_boring_long_name")
.SetAnyNumberOfArgumentsButAtleastOne()
.SetType(argparse::ArgTypeCast::e_int)
.SetHelp("some_boring_long_name description with some important information for user.")
.SetRequired(false));
auto obj = parser.ParseArgs(argc, argv);
if (obj.IsArgValid())
{
auto arg = obj.GetArg("numbers");
if (arg.GetArgumentExists())
{
for (auto& el : arg.GetAsVecInt())
{
std::cout << el << std::endl;
}
}
}
else
{
std::string help = parser.GetHelp(80);
std::cout << obj.GetErrorString() << std::endl;
std::cout << help << std::endl;
}
return 0;
}This exmaple will create program with keys -n, --number, -s, --some_boring_long_name, -h and --help. Help will be autogenerated. The types of numbers and some_boring_long_name are integers with count from 1 to infinite.
Typical output without any arguments:
main.cpp [-n,--numbers [n ...] ] [-s,--some_boring_long_name [s ...] ] -h,--help
Description of program
optional arguments:
-n,--numbers some numbers description with some important information
for user. Type: INT. Args count: at least one.
-s,--some_boring_long_name
some_boring_long_name description with some important information
for user. Type: INT. Args count: at least one.
-h,--help Show help!
Note actually terminal cannot get infinite numbers of arguments. In most cases maximum length of all input that terminal can pass is limited with 8 kb.
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser(__FILE__).SetDescription("Description of program");
parser.AddArgument(argparse::CreateNamedArgument("n", "numbers", argparse::kFromOneToInfinteArgCount,
argparse::ArgTypeCast::e_int, false,
"some numbers description with some important information for user."));
parser.AddArgument(argparse::CreateNamedArgument("s", "some_boring_long_name", argparse::kFromOneToInfinteArgCount,
argparse::ArgTypeCast::e_int, false,
"some_boring_long_name description with some important information for user."));
auto obj = parser.ParseArgs(argc, argv);
if (obj.IsArgValid())
{
auto arg = obj.GetArg("numbers");
if (arg.GetArgumentExists())
{
for (auto& el : arg.GetAsVecInt())
{
std::cout << el << std::endl;
}
}
}
else
{
std::string help = parser.GetHelp(80);
std::cout << obj.GetErrorString() << std::endl;
std::cout << help << std::endl;
}
return 0;
}
generic -h, --help is suppressed example compiles for c++17 and uses std::any approach
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser("main").SetDescription("ArgParse example");
parser.AddArgument(argparse::CreateNamedArgument("b", "b_key", 1, argparse::ArgTypeCast::e_int, true,
R"=(some "b_key" description with some important information for user)="));
parser.SetAddHelp(false);
auto obj = parser.ParseArgs(argc, argv);
if (obj.IsArgValid())
{
auto arg = obj.GetArg("b_key");
std::cout << arg.Get().type().name() << ": " << std::any_cast<int>(arg.Get()) << std::endl;
}
else
{
std::string help = parser.GetHelp(80);
std::cout << obj.GetErrorString() << std::endl;
std::cout << help << std::endl;
}
return 0;
}You can change 1 to 0 from this example. It will be flag, and you cannot access to it's content.
Positional argument should be inputted as raw argument without any key. This is only difference between keyed and positional arguments.
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser("main").SetDescription("ArgParse example");
parser.AddArgument(argparse::CreatePositionalArgument("int1")
.SetType(argparse::ArgTypeCast::e_int).SetRequired(false));
auto obj = parser.ParseArgs(argc, argv);
if (obj.IsArgValid())
{
auto arg = obj.GetArg("int1");
if (arg.GetArgumentExists())
{
std::cout << arg.Get().type().name() << ": " << std::any_cast<int>(arg.Get()) << std::endl;
}
}
else
{
std::string help = parser.GetHelp(80);
std::cout << obj.GetErrorString() << std::endl;
std::cout << help << std::endl;
}
return 0;
}
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser("main").SetDescription("ArgParse example");
parser.AddArgument(argparse::CreatePositionalArgument("nums").SetType(argparse::ArgTypeCast::e_double).SetNumberOfArguments(2));
parser.AddArgument(argparse::CreateNamedArgument("o", "operation").SetRequired(true).SetChoices({"+","-","*","/"}));
parser.SetEpilogue("This is example of epilogue. Will be placed in the end of help");
auto obj = parser.ParseArgs(argc, argv);
if (obj.IsArgValid())
{
auto arg = obj.GetArg("nums");
auto op = obj.GetArg("operation");
const std::vector<double>& nums = arg.GetAsVecDouble();
const std::string& operation = op.GetAsString();
std::cout << nums[0] << operation << nums[1] << "=";
if (operation == "+")
{
std::cout << nums[0] + nums[1] << std::endl;
}
else if (operation == "-")
{
std::cout << nums[0] - nums[1] << std::endl;
}
else if (operation == "*")
{
std::cout << nums[0] * nums[1] << std::endl;
}
else //if(operation == "/")
{
std::cout << nums[0] / nums[1] << std::endl;
}
}
else
{
std::string help = parser.GetHelp(80);
std::cout << obj.GetErrorString() << std::endl;
std::cout << help << std::endl;
}
return 0;
}usage examples
>>> calc.exe 12121 222 -o +
12121+222=12343
>>> calc.exe 12121 222 -o %
Value '%' is out of choices for "operation"
main nums [nums nums] -o,--operation [{+, -, *, /}] [-h,--help]
ArgParse example
positional arguments:
nums Type: DOUBLE. Args count: 2
named arguments:
-o,--operation Type: STRING. Choices:+, -, *, /. Args count: 1
-h,--help Show help!
This is example of epilogue. Will be placed in the end of help
A flag holds no value — it is either present or not — created with SetArgumentIsFlag().
Remember that every argument is required by default, so an optional flag must opt
out with SetRequired(false). SetDefault(...) gives an optional argument a value to
fall back on when the user omits it.
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser("build").SetDescription("Flags and default values");
parser.AddArgument(argparse::CreateNamedArgument("v", "verbose").SetArgumentIsFlag()
.SetRequired(false)
.SetHelp("Enable verbose output"));
parser.AddArgument(argparse::CreateNamedArgument("j", "jobs", 1, argparse::ArgTypeCast::e_int, false)
.SetDefault(1)
.SetHelp("Number of parallel jobs (default: 1)"));
auto obj = parser.ParseArgs(argc, argv);
if (!obj.IsArgValid())
{
std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
return 1;
}
const bool verbose = obj.GetArg("verbose").GetArgumentExists();
const int jobs = obj.GetArg("jobs").GetAsInt(); // always present thanks to SetDefault
std::cout << "verbose = " << (verbose ? "true" : "false") << "\n";
std::cout << "jobs = " << jobs << std::endl;
return 0;
}>>> build -v
verbose = true
jobs = 1
>>> build
verbose = false
jobs = 1
Positional and named arguments can be combined freely. Below, a small cp-like tool
takes two positionals (source, dest) and one named flag (-f/--force).
Important: getters that return a reference —
GetAsString()and theGetAsVec*()family — return a reference into theArgumentParsedobject. Store the result ofGetArg(...)in a variable before calling them, otherwise the reference dangles. (Value getters likeGetAsInt()/GetAsDouble()return by value and are always safe.)
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser("mycp").SetDescription("Copy SOURCE to DEST");
parser.AddArgument(argparse::CreatePositionalArgument("source").SetHelp("File to copy from"));
parser.AddArgument(argparse::CreatePositionalArgument("dest").SetHelp("File to copy to"));
parser.AddArgument(argparse::CreateNamedArgument("f", "force").SetArgumentIsFlag()
.SetRequired(false)
.SetHelp("Overwrite destination if it exists"));
auto obj = parser.ParseArgs(argc, argv);
if (!obj.IsArgValid())
{
std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
return 1;
}
// Store the ArgumentParsed before reading string references from it.
auto sourceArg = obj.GetArg("source");
auto destArg = obj.GetArg("dest");
const std::string& src = sourceArg.GetAsString();
const std::string& dst = destArg.GetAsString();
const bool force = obj.GetArg("force").GetArgumentExists();
std::cout << "copy " << src << " -> " << dst << (force ? " (force)" : "") << std::endl;
return 0;
}>>> mycp a.txt b.txt -f
copy a.txt -> b.txt (force)
There are two distinct kinds of errors:
-
Setup errors — a malformed definition, e.g. an argument with neither a name nor a
positional name.
AddArgumentthrows for these; they are programmer mistakes. You only need atry/catchif you build arguments dynamically from external data. -
Input errors — bad user input (missing required argument, wrong type, value out of
choices). These are never thrown; they are reported through the result object via
IsArgValid()andGetErrorString().
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
argparse::ArgumentParser parser("app");
try
{
parser.AddArgument(argparse::CreateNamedArgument("p", "port", 1, argparse::ArgTypeCast::e_int, true)
.SetHelp("Port to listen on"));
}
catch (const std::exception& e)
{
std::cerr << "argument setup error: " << e.what() << std::endl;
return 2;
}
auto obj = parser.ParseArgs(argc, argv);
if (!obj.IsArgValid())
{
std::cerr << "error: " << obj.GetErrorString() << "\n\n";
std::cerr << parser.GetHelp(80) << std::endl;
return 1;
}
std::cout << "listening on port " << obj.GetArg("port").GetAsInt() << std::endl;
return 0;
}>>> app -p 8080
listening on port 8080
>>> app
error: Required argument with name "port" doesn't exists
app -p,--port [p] [-h,--help]
named arguments:
-p,--port Port to listen on Type: INT. Args count: 1
-h,--help Show help!
Combines a typed positional (double), two required named arguments constrained with
SetChoices, and an epilogue.
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser("convert").SetDescription("Convert a temperature between units");
parser.AddArgument(argparse::CreatePositionalArgument("value")
.SetType(argparse::ArgTypeCast::e_double).SetHelp("Temperature value"));
parser.AddArgument(argparse::CreateNamedArgument("f", "from").SetRequired(true)
.SetChoices({"C", "F", "K"}).SetHelp("Source unit"));
parser.AddArgument(argparse::CreateNamedArgument("t", "to").SetRequired(true)
.SetChoices({"C", "F", "K"}).SetHelp("Target unit"));
parser.SetEpilogue("Units: C = Celsius, F = Fahrenheit, K = Kelvin");
auto obj = parser.ParseArgs(argc, argv);
if (!obj.IsArgValid())
{
std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
return 1;
}
auto fromArg = obj.GetArg("from");
auto toArg = obj.GetArg("to");
const double v = obj.GetArg("value").GetAsDouble(); // returns by value: safe inline
const std::string& from = fromArg.GetAsString();
const std::string& to = toArg.GetAsString();
double c = from == "C" ? v : from == "F" ? (v - 32.0) * 5.0 / 9.0 : v - 273.15;
double out = to == "C" ? c : to == "F" ? c * 9.0 / 5.0 + 32.0 : c + 273.15;
std::cout << v << from << " = " << out << to << std::endl;
return 0;
}>>> convert 100 -f C -t F
100C = 212F
>>> convert 100 -f C -t Q
Value 'Q' is out of choices for "to"
kAnyArgCount accepts zero or more values (use kFromOneToInfinteArgCount to demand at
least one). SetPrefixChars('+') changes the option prefix, and SetIgnoreUknownArgs(true)
lets the parser skip options it doesn't recognise instead of failing.
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser("sum")
.SetDescription("Sum any amount of numbers")
.SetPrefixChars('+')
.SetIgnoreUknownArgs(true);
parser.AddArgument(argparse::CreateNamedArgument("n", "nums", argparse::kAnyArgCount,
argparse::ArgTypeCast::e_int, false).SetHelp("Numbers to add"));
auto obj = parser.ParseArgs(argc, argv);
if (!obj.IsArgValid())
{
std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
return 1;
}
long long total = 0;
auto arg = obj.GetArg("nums");
if (arg.GetArgumentExists())
for (int n : arg.GetAsVecInt())
total += n;
std::cout << "sum = " << total << std::endl;
return 0;
}>>> sum ++nums 3 4 5 ++junk hello
sum = 12
If the default argparse namespace clashes with something in your project, define
ARGPARSE_NAMESPACE_NAME before including the header to rename it.
#define ARGPARSE_NAMESPACE_NAME cli
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = cli::ArgumentParser("greet").SetDescription("Custom namespace demo");
parser.AddArgument(cli::CreateNamedArgument("n", "name", 1, cli::ArgTypeCast::e_String, true)
.SetHelp("Who to greet"));
auto obj = parser.ParseArgs(argc, argv);
if (!obj.IsArgValid())
{
std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
return 1;
}
std::cout << "Hello, " << obj.GetArg("name").GetAsString() << "!" << std::endl;
return 0;
}>>> greet --name World
Hello, World!
Use ArgTypeCast::e_bool for arguments whose value is a boolean. The accepted
spellings are true/True/TRUE and false/False/FALSE. (If you want a
valueless on/off switch rather than a typed value, use SetArgumentIsFlag() —
see Flags and default values above.)
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser("feature").SetDescription("Bool-typed arguments");
parser.AddArgument(argparse::CreateNamedArgument("d", "debug", 1,
argparse::ArgTypeCast::e_bool, false).SetDefault(false)
.SetHelp("Enable debug mode (true/false)"));
// A bool argument can also take several values.
parser.AddArgument(argparse::CreateNamedArgument("s", "switches",
argparse::kFromOneToInfiniteArgCount, argparse::ArgTypeCast::e_bool, false)
.SetHelp("A series of on/off switches"));
auto obj = parser.ParseArgs(argc, argv);
if (!obj.IsArgValid())
{
std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
return 1;
}
std::cout << "debug = " << (obj.GetArg("debug").GetAsBool() ? "true" : "false") << "\n";
auto sw = obj.GetArg("switches");
if (sw.GetArgumentExists())
{
std::cout << "switches =";
for (bool b : sw.GetAsVecBool())
std::cout << ' ' << (b ? "on" : "off");
std::cout << std::endl;
}
return 0;
}>>> feature --debug true --switches true false TRUE
debug = true
switches = on off on
By default the usage line is generated from your arguments. SetUsage(...)
replaces just that first line with your own wording; the positional/named
argument listings below it are still generated for you.
#include <iostream>
#include "ArgParse/argparse.h"
int main(int argc, char** argv)
{
auto parser = argparse::ArgumentParser("serve").SetDescription("Start a web server");
parser.SetUsage("serve --port PORT [--host HOST]");
parser.AddArgument(argparse::CreateNamedArgument("p", "port", 1,
argparse::ArgTypeCast::e_int, true).SetHelp("Port to listen on"));
parser.AddArgument(argparse::CreateNamedArgument("H", "host", 1,
argparse::ArgTypeCast::e_String, false).SetDefault(std::string("0.0.0.0"))
.SetHelp("Interface to bind"));
auto obj = parser.ParseArgs(argc, argv);
if (!obj.IsArgValid())
{
std::cout << obj.GetErrorString() << "\n" << parser.GetHelp(80) << std::endl;
return 1;
}
auto host = obj.GetArg("host");
std::cout << "listening on " << host.GetAsString()
<< ":" << obj.GetArg("port").GetAsInt() << std::endl;
return 0;
}>>> serve --port 8080
listening on 0.0.0.0:8080
>>> serve
Required argument with name "port" doesn't exists
serve --port PORT [--host HOST]
Start a web server
named arguments:
-p,--port Port to listen on Type: INT. Args count: 1
-H,--host Interface to bind Type: STRING. Args count: 1
-h,--help Show help!
Tip: put positional arguments before named ones on the command line. The parser collects positionals first, so
mytool FILE --flagworks whilemytool --flag FILEmay misassignFILE.