TAP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
The Argument Parser

Introduction

This is TAP, a library for command line argument parsing ala get_opt_long(). It is a header-only library with a bunch of templated classes that ought to make argument parsing simple. The main reasons for the existence of this library:

Try before you buy, check some of the examples, and otherwise look at for instance boost::program_options, TCLAP, get_opt() (ha), "The Lean Mean C++ Option Parser", cpp-optparse, or just check http://stackoverflow.com/questions/865668/parse-command-line-arguments.

Installation

As this is a header-only library, no install is necessary. Just drop the directory 'tap' with all headers somewhere in your include path, and all should be fine.

Usage

To use the library, first add a

#include <tap/Tap.h>

to your sources, then simply code away. All members of TAP are defined in the TAP namespace.

Quickstart:

#include <tap/Tap.h>
#include <iostream>
int main(int argc, const char* argv[]) {
TAP::Argument badExit("If set, exit with non-zero status", 'x', "badexit");
TAP::ArgumentParser parser(badExit);
try {
parser.parse(argc, argv);
} catch (TAP::exception& e) {
std::cerr << e.what() << std::endl;
return 1;
}
if (badExit) {
// The argument was set
std::cout << "Just, why?" << std::endl;
return 1;
}
return 0;
}

Tutorial and examples

Argument parsing starts with defining a number of TAP::Argument instances, adding them to an TAP::ArgumentParser, and passing along the actual program arguments (as received from main()) to the parser. If all goes well, you can read in the parsed data from the arguments, otherwise an TAP::exception will be thrown.

The examples below assume TAP_AUTOFLAG has been defined, see Configuration for details.

Defining arguments

At the basic level, an argument consists of a description, and zero or more aliases. Aliases can be used to name the argument on the command line, either as a flag or as a name (see TAP::ArgumentParser for details). One particular remark about aliases: If an argument is created without an alias, it is marked as positional. Any alias defined later does not change this. This allows positional arguments to be defined, that can also be accessed via a name or flag.

The description can be used to define aliases as well. To do so, mark the flags or names to use in the description (see TAP::Argument::parse_description()). You can use this to save on typing when defining arguments.

Multiple argument classes exist that can be used, in short they are

Required arguments and argument counts

By default, all arguments are optional, and can occur at most once. To change this behavior, each argument has the following functions:

Regular arguments by default are optional and can occur at most once. Multi* arguments can occur many times. Note that for most TypedArgument types (except Multi*), if the argument is allowed to occur multiple times, its value is overwritten on each occurrence.

A common occurrence of arguments that are allowed to occur multiple times, but sometimes limited, are verbosity or debugging level arguments. For example:

TAP::Argument verbosity("Set the verbosity level", 'v', "verbose");
verbosity.max(3); // alternatively: many()
...
if (verbosity) {
unsigned int verbosityLevel = verbosity.count();
}

Note that there is a (small) semantic difference between a required argument and the minimum number of occurrences. If required() is true, this only means the argument has to occur somewhere. The min() value dictates how many times. If required() is false, the argument is also alowed to be absent, even if min is not zero. In fact, min is required to be always at least 1.

Argument callbacks

It is possible to assign a callback to an TAP::Argument that is called whenever the argument is set. For example:

TAP::Argument help("Show this &help text");
TAP::ArgumentParser parser(help);
help.check([&parser](const TAP::Argument&) -> void {
std::cout << parser.help() << std::endl; exit(1);
});

For details see TAP::Argument::check() and TAP::ArgumentCheckFunc.

Similarly, TAP::TypedArgument also allows for a callback with the value that was set, for example:

TAP::ValueArgument<int> answer("Set the &answer");
TAP::ArgumentParser parser(answer);
answer.check([&parser](const TAP::TypedArgument<int>&, int val) -> void {
if (val != 42) {
throw TAP::exception("That is not the answer");
}
});

For details see TAP::TypedArgument::check() and TAP::TypedArgumentCheckFunc.

Argument constraints

Every now and then some arguments can only occur in certain combinations or have some sort of constraint associated with them (aside from the number of occurrences allowed or required, see Required arguments and argument counts). To specify this, arguments can be added (recursively) into TAP::ArgumentConstraint instances, which specify a certain constraint on the occurrences of arguments relative to each other. Most commonly, exactly one argument must be selected out of a group of many.

To specify such a constraint, create an instance of TAP::ArgumentConstraint, templated to TAP::ConstraintType to specify which constraint, and add the constrained arguments. For example:

TAP::Argument left("Turn &left");
TAP::Argument right("Turn &right");
TAP::Argument help("Show this &help text");
TAP::ArgumentParser parser(dir, help);

In this example, left and right cannot be set both at the same time. Should either left or right be selected (so selecting neither is invalid), set the constraint as required with set_required().

Note: Be careful when adding arguments that are required to constraints with an upper bound on the number of allowed arguments (such as TAP::ConstraintType::One). This can lead to situations where the constraint can never be satisfied, as all of its arguments are required, but the constraint prohibits this.

Operators

For the common case of mutually exclusive arguments, the hat operator (binary XOR) has been defined for arguments to create a TAP::ConstraintType::One constraint of the given arguments. For example:

TAP::Argument left("Turn &left");
TAP::Argument right("Turn &right");
TAP::Argument help("Show this &help text");
TAP::ArgumentParser parser(left ^ right, help);

Similarly, the OR operator (|) is defined for TAP::ConstraintType::Any, and the AND operator (&) is defined for TAP::ConstraintType::All.

Furthermore, unary operators + and - set an argument respectively as required or optional. Thus, in the above example, to require exactly left or right to be set, you can use:

TAP::ArgumentParser parser(+(left ^ right), help);

Parsing arguments

Parsing arguments is relatively straight-forward. After defining all arguments and an argument parser, with the arguments added to the parser, simply invoke TAP::ArgumentParser::parse and done. If an error occurs, an exception of the type TAP::exception (or a subclass thereof) will be thrown.

int main(int argc, char** argv) {
TAP::Argument help("Show this &help text");
TAP::Argument version("Show &version information");
TAP::ArgumentParser parser(help, version);
parser.parse(argc, argv);
if (help) {
std::cout << parser.help() << std::endl;
} else if(version) {
std::cout << "FIXME" << std::endl;
}
return 0;
}

Arguments can be added either in the constructor, or using the TAP::ArgumentParser::add() method.

Argument groups

To group arguments (useful mostly for the help text) a TAP::ArgumentSet can be created (similar to a constraint), with a given name. When added to the parser, its children are grouped separately in the help text.

Argument testing and value retrieval

To determine if an argument is set, converting to bool is possible, e.g.

TAP::Argument myArg("&test");
if (myArg) {
...
}

Keep in mind that for arguments that actually store a bool, this is not the same as its value.

To get the number of occurrences, see the TAP::Argument::count() method. For TAP::TypedArgument instances, the value can be retrieved using TAP::TypedArgument::value(). Note that for Multi valued arguments, the value is automatically set to a vector.

Configuration

TAP allows for some configuration in the main header file. The following settings alter some of its behavior:

Aside from these options, other defines allow some of the syntax to be tweaked (see Tap.h for more details):

Quirks

Though the library is intended to use relatively easy to use, it may not always do what is expected. Some quirks are listed here:

Known issues