Copyright © 2017-2021 Google LLC
Copyright © 2012-2016 Daniel Aarno
Copyright © 2003-2012 Michael E. Smoot
Table of Contents
Table of Contents
TCLAP has a few key classes to be aware of.
The first is the
CmdLine (command line) class. This class parses
the command line passed to it according to the arguments that it
contains. Arguments are separate objects that are added to the
CmdLine object one at a time. The six
argument classes are: ValueArg,
UnlabeledValueArg,
SwitchArg, MultiSwitchArg,
MultiArg and
UnlabeledMultiArg.
These classes are templatized, which means they can be defined to parse
a value of any type. Once you add the
arguments to the CmdLine object, it parses the
command line
and assigns the data it finds to the specific argument objects it
contains. Your program accesses the values parsed by
calls to the getValue() methods of the
argument objects.
Here is a simple example ...
#include <string>
#include <iostream>
#include <algorithm>
#include <tclap/CmdLine.h>
int main(int argc, char** argv)
{
// Wrap everything in a try block. Do this every time,
// because exceptions will be thrown for problems.
try {
// Define the command line object, and insert a message
// that describes the program. The "Command description message"
// is printed last in the help text. The second argument is the
// delimiter (usually space) and the last one is the version number.
// The CmdLine object parses the argv array based on the Arg objects
// that it contains.
TCLAP::CmdLine cmd("Command description message", ' ', "0.9");
// Define a value argument and add it to the command line.
// A value arg defines a flag and a type of value that it expects,
// such as "-n Bishop".
TCLAP::ValueArg<std::string> nameArg("n","name","Name to print",true,"homer","string");
// Add the argument nameArg to the CmdLine object. The CmdLine object
// uses this Arg to parse the command line.
cmd.add( nameArg );
// Define a switch and add it to the command line.
// A switch arg is a boolean argument and only defines a flag that
// indicates true or false. In this example the SwitchArg adds itself
// to the CmdLine object as part of the constructor. This eliminates
// the need to call the cmd.add() method. All args have support in
// their constructors to add themselves directly to the CmdLine object.
// It doesn't matter which idiom you choose, they accomplish the same thing.
TCLAP::SwitchArg reverseSwitch("r","reverse","Print name backwards", cmd, false);
// Parse the argv array.
cmd.parse( argc, argv );
// Get the value parsed by each arg.
std::string name = nameArg.getValue();
bool reverseName = reverseSwitch.getValue();
// Do what you intend.
if ( reverseName )
{
std::reverse(name.begin(),name.end());
std::cout << "My name (spelled backwards) is: " << name << std::endl;
}
else
std::cout << "My name is: " << name << std::endl;
} catch (TCLAP::ArgException &e) // catch exceptions
{ std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
}
The output should look like:
% test1 -n mike
My name is: mike
% test1 -n mike -r
My name (spelled backwards) is: ekim
% test1 -r -n mike
My name (spelled backwards) is: ekim
% test1 -r
PARSE ERROR:
One or more required arguments missing!
Brief USAGE:
test1 [-r] -n <string> [--] [-v] [-h]
For complete USAGE and HELP type:
test1 --help
% test1 --help
USAGE:
test1 [-r] -n <string> [--] [-v] [-h]
Where:
-r, --reverse
Print name backwards
-n <string> --name <string>
(required) (value required) Name to print
--, --ignore_rest
Ignores the rest of the labeled arguments following this flag.
-v, --version
Displays version information and exits.
-h, --help
Displays usage information and exits.
Command description message
This example shows a number of different properties of the library...
help, version
and --SwitchArgs
are specified automatically. Using either the -h or
--help flag will cause the USAGE message to be displayed,
-v or --version will cause
any version information to
be displayed, and -- or
--ignore_rest will cause the
remaining labeled arguments to be ignored. These switches are
included by default on every command line. You can disable this functionality if desired (although we don't recommend it).
-s=asdf instead of
-s asdf, you can do so.CmdLine, constructing the Args,
or parsing the command line will throw an
ArgException.
Arguments, whatever their type, have a few common properties. These properties are set in the constructors of the arguments.
getopt_long()].
Each CmdLine owns its delimiter and positional
registration checks. Optional positional arguments must be registered last;
constructing an unregistered argument does not affect another parser.
Use separate argument objects for separate parsers and keep the parser alive
while using its registered arguments. Custom argument implementations should
use getDelimiter(), which observes their parser's
delimiter. The legacy static Arg::delimiter() and
Arg::setDelimiter() remain available for unregistered
arguments and legacy custom code, but do not select a registered parser's
delimiter. The legacy OptionalUnlabeledTracker static
helper is no longer used by the built-in arguments.
Failed registration leaves the parser's argument list, required count,
positional checks, delimiter bindings and group membership unchanged.
A group rejected during attachment can be retried on another parser.
Custom addToList() hooks receive a temporary list
with the owning delimiter already bound; do not retain that list or re-enter
registration. Application side effects in custom hooks are not rolled back.
Custom CmdLineInterface implementations retain the
legacy attachment default and can override the protected
attachGroup() hook for their own transaction handling.
add() borrows its argument; it does not copy it or
transfer ownership. Keep caller-owned arguments alive while the parser uses
them. Constraints and custom output objects passed to
setOutput() are also borrowed and must remain alive
while used. Declare dependencies before the objects that refer to them. This
example declares the constraint and output first, the argument next, and the
parser last, so destruction happens in the reverse order:
#include <tclap/CmdLine.h>
#include <tclap/ValuesConstraint.h>
#include <tclap/StdOutput.h>
#include <vector>
int main(int argc, char **argv) {
std::vector<int> allowed;
allowed.push_back(1);
allowed.push_back(2);
TCLAP::ValuesConstraint<int> choices(allowed);
TCLAP::StdOutput output;
TCLAP::ValueArg<int> count("n", "number", "Choose a number",
false, 1, &choices);
TCLAP::CmdLine cmd("example");
cmd.setOutput(&output);
cmd.add(count);
cmd.parse(argc, argv);
return 0;
}
Visitor objects supplied to arguments are borrowed and must remain alive when invoked. Groups passed to the parser are also borrowed. Use distinct argument objects for separate live parsers. Keep the parser alive while using registered arguments' delimiter bindings.
An attached delimiter can carry an empty value, for example
--name= when the parser delimiter is =.
With the default space delimiter, pass an empty argv element (for example,
--name "" in a shell). Strings and types with
StringLike traits receive the empty string directly.
Numeric values reject empty input. Custom stream extractors decide whether
empty input is valid through their operator>>
implementation; no default-value substitution is performed.
Constraints still check explicitly supplied values, including empty strings.
These rules apply to both ValueArg and
MultiArg. Omitting a value entirely is still an error.
For installed CMake consumers, use
find_package(TCLAP CONFIG REQUIRED) and link your application
target with target_link_libraries(app PRIVATE TCLAP::TCLAP).
Use CMAKE_PREFIX_PATH for a custom installation prefix, or
TCLAP_DIR for a nonstandard package metadata directory. See
INSTALL in the source root for a complete example.
The imported target propagates the C++20 language requirement.
TCLAP is implemented entirely in header files which means you only need to include CmdLine.h to use the library.
#include <tclap/CmdLine.h>
You'll need to make sure that your compiler can see the header files. If you do the usual "make install" then your compiler should see the files by default. Alternatively, you can use the -I complier argument to specify the exact location of the libraries.
c++ -std=c++20 -o my_program -I /some/place/tclap-1.6/include my_program.cpp
Where /some/place/tclap-1.6 is the place you have unpacked the distribution.
Finally, if you want to include TCLAP as part of your software (which is perfectly OK, even encouraged) then simply copy the contents of /some/place/tclap-1.6/include (the tclap directory and all of the header files it contains) into your include directory. The necessary m4 macros for proper configuration are included in the config directory.
TCLAP 1.6 requires a C++20 compiler and a C++20
standard library that provides std::format.
It retains the 1.4-style API while using C++20 internally.
For C++98 projects, use TCLAP 1.4. TCLAP 1.2 remains available for existing
integrations that require its legacy API and behavior.
The CmdLine class contains the arguments that define
the command line and manages the parsing of the command line. The
CmdLine doesn't parse the command line itself it only
manages the parsing. The actual parsing of individual arguments occurs within
the arguments themselves. The CmdLine keeps track of
of the required arguments, relationships
between arguments, and output generation.
SwitchArgs are what the name implies:
simple, on/off, boolean switches. Use SwitchArgs
anytime you want to turn
some sort of system property on or off. SwitchArgs
don't parse a value. They return TRUE or
FALSE, depending on whether the switch has been found
on the command line and what the default value was defined as.
ValueArgs are arguments that read a
value of some type
from the command line. Any time you need a file name, a number,
etc. use a ValueArg or one of its variants.
All ValueArgs are
templatized and will attempt to parse
the string its flag matches on the command line as the type it is
specified as. ValueArg<int>
will attempt to parse an
int, ValueArg<float> will attempt to
parse a float, etc. If operator>>
for the specified type doesn't
recognize the string on the command line as its defined type, then
an exception will be thrown.
A MultiArg is a ValueArg that
can be specified more than once on a command line and instead of returning
a single value, returns a vector of values.
Imagine a compiler that allows you to specify multiple directories to search for libraries...
% fooCompiler -L /dir/num1 -L /dir/num2 file.foo
Exceptions will occur if you try to do this
with a ValueArg or a SwitchArg.
In situations like this, you will want to use a
MultiArg. A
MultiArg is essentially a
ValueArg that appends any
value that it matches and parses onto a vector of values. When the
getValue() method is called, a vector of
values, instead of a single value is returned. A
MultiArg is declared much like
a ValueArg:
MultiArg<int> itest("i", "intTest", "multi int test", false,"int" );
cmd.add( itest );
Note that MultiArgs can be added to the
CmdLine in any order (unlike
UnlabeledMultiArg).
A MultiSwitchArg is a SwitchArg
that can be specified more than once on a command line.
This can be useful
when command lines are constructed automatically from within other applications
or when a switch occurring
more than once indicates a value (-V means a little verbose -V -V -V means a lot
verbose), You can use a MultiSwitchArg.
The call
to getValue() for a MultiSwitchArg returns the number (int) of times
the switch has been found on the command line in addition to the default value.
Here is an example using the default initial value of 0:
MultiSwitchArg quiet("q","quiet","Reduce the volume of output");
cmd.add( quiet );
Alternatively, you can specify your own initial value:
MultiSwitchArg quiet("q","quiet","Reduce the volume of output",5);
cmd.add( quiet );
An UnlabeledValueArg is a ValueArg that is not identified by a flag on the command line. Instead
UnlabeledValueArgs are identified by their position in
the argv array.
To this point all of our arguments have had labels (flags)
identifying them on the command line, but there are some
situations where flags are burdensome and not worth the effort. One
example might be if you want to implement a magical command we'll
call copy. All copy does is
copy the file specified
in the first argument to the file specified in the second argument.
We can do this using UnlabeledValueArgs which are pretty
much just ValueArgs without the flag specified,
which tells
the CmdLine object to treat them accordingly.
The code would look like this:
UnlabeledValueArg<float> nolabel( "name", "unlabeled test", true, 3.14,
"nameString" );
cmd.add( nolabel );
Everything else is handled identically to what is seen above. The
only difference to be aware of, and this is important: the order
that UnlabeledValueArgs are added to the CmdLine
is the order that they will be parsed!!!!
This is not the case for normal
SwitchArgs and ValueArgs.
What happens internally is the first argument that the
CmdLine doesn't recognize is assumed to be
the first UnlabeledValueArg and
parses it as such. Note that you are allowed to intersperse labeled
args (SwitchArgs and ValueArgs) in between
UnlabeledValueArgs (either on the command line
or in the declaration), but the UnlabeledValueArgs
will still be parsed in the order they are added. Just remember that order is
important for unlabeled arguments.
An UnlabeledMultiArg is an UnlabeledValueArg that allows more than one value to be specified. Only one
UnlabeledMultiArg can be specified per command line.
The UnlabeledMultiArg simply reads the remaining
unmatched operand values through the end of argv, including values after
-- with its normal non-ignoreable setting. The marker
itself is consumed by the parser. See end option
recognition for the ignoreable policy and branch-specific limitations.
Say you want a strange command that searches each file specified for a given string (let's call it grep), but you don't want to have to type in all of the file names or write a script to do it for you. Say,
% grep pattern *.txt
First remember that the * is handled by the shell and expanded accordingly, so what the program grep sees is really something like:
% grep pattern file1.txt file2.txt fileZ.txt
To handle situations where multiple, unlabeled arguments are needed,
we provide the UnlabeledMultiArg.
UnlabeledMultiArgs
take an explicit required constructor boolean; there
is no default for that choice. With true, at least one operand must be supplied
or parsing fails. With false, omission is allowed and
getValue() returns an empty vector. The example below
chooses false. The most important thing to remember is,
that like UnlabeledValueArgs: order matters!
In fact, an UnlabeledMultiArg must be the last argument added to the
CmdLine!. Here is what a declaration looks like:
//
// UnlabeledMultiArg must be the LAST argument added!
//
UnlabeledMultiArg<string> multi("fileNames", "file names", false, "string");
cmd.add( multi );
cmd.parse(argc, argv);
vector<string> fileNames = multi.getValue();
You must only ever specify one (1) UnlabeledMultiArg.
One UnlabeledMultiArg will read every unlabeled
Arg that wasn't already processed by a
UnlabeledValueArg into a
vector of type T. Any
UnlabeledValueArg or other
UnlabeledMultiArg specified after the first
UnlabeledMultiArg will be ignored, and if
they are required,
exceptions will be thrown. When you call the
getValue()
method of the UnlabeledValueArg argument,
a vector
will be returned. If you can imagine a situation where there will
be multiple args of multiple types (stings, ints, floats, etc.)
then just declare the UnlabeledMultiArg as type
string and parse the different values yourself or use
several UnlabeledValueArgs.
Table of Contents
Naturally, what we have seen to this point doesn't satisfy all of our needs.
Multiple SwitchArgs can be combined into a
single argument on the command line. If you have switches -a, -b and -c
it is valid to do either:
% command -a -b -c
or
% command -abc
or
% command -ba -c
This is to make this library more in line with the POSIX and GNU standards (as I understand them).
Suppose you have a command that must read input from one of two
possible locations, either a local file or a URL. The command
must read something, so one
argument is required, but not both, yet neither argument is strictly
necessary by itself.
TCLAP can automatically enforce such constraints on a set of arguments
using an argument group of type OneOf.
ValueArg<string> fileArg("f","file","File name to read",false,"/dev/zero", "filename");
ValueArg<string> urlArg("u","url","URL to load",false, "http://example.com", "URL");
OneOf input;
input.add(fileArg).add(urlArg);
cmd.add(input);
cmd.parse(argc, argv);
If the Arg has been matched on the command
line, the isSet() will return
TRUE.
if ( fileArg.isSet() )
readFile( fileArg.getValue() );
else if ( urlArg.isSet() )
readURL( urlArg.getValue() );
else
// Should never get here because TCLAP will note that one of the
// required args above has not been set.
throw("Very bad things...");
It is helpful to note that Args of any type can
be part of the same argument group This means that you can add a
SwitchArg and a
ValueArg. This is helpful in situations where
one of several options is necessary and one of the options requires
additional information.
There is also the class EitherOf that works the
same way, except it does not require any argument to be set. This can
be useful if there is a natural default. For example, selecting the
encryption algorithm may default to AES, but there may be flags for
choosing another algorithm and they are all mutually exclusive.
AnyOf groups arguments for presentation only. It does
not require a member to be selected or make one member depend on another.
Each argument's own requirements still apply; check any conditional
dependencies in application code after a successful parse.
Some commands have so many options that single flags no longer map
sensibly to the available options. In this case, it is desirable to
specify Args using only long options. This one is easy to
accomplish, just make the flag value blank in the Arg
constructor. This will tell the Arg that only the long
option should be matched and will force users to specify the long
option on the command line. The help output is updated accordingly.
ValueArg<string> fileArg("","file","File name",true,"homer","filename");
SwitchArg caseSwitch("","upperCase","Print in upper case",false);
Each argument name must be unique within a parser, including names of
positional arguments. Nonempty short flags must also be unique. Short flags
and long names are separate namespaces: one argument can use
-x while another uses --x. Registering the same
argument object twice is rejected. Descriptions are presentation text and
may be identical or empty without causing a conflict.
These checks also apply when adding arguments to groups and attaching groups to a parser. They do not change the separate rules for positional ordering or exclusive groups. Failed registration leaves the parser and group membership unchanged.
Use arg.conflictsWith(other) to check for conflicting
declarations, or compare addresses to check whether two references identify
the same object. The legacy virtual equality operator is retained for source
compatibility, including its positional description comparisons, but no longer
controls registration or exclusive group selection. The conflict rule is
nonvirtual and applies to custom arguments through their declared names and
flags; additional tokens recognized by a custom processArg()
are not inferred by registration. Custom equality overrides that previously
changed duplicate detection must adapt to this declared-name-and-flag rule.
Stream-extracted values (ValueLike) reject embedded
NUL bytes by default. This includes numeric, boolean and character values,
and custom types using operator>>. For example, an integer
token containing the bytes 42\0junk is rejected instead of
being silently read as 42. This matters when supplying
std::string tokens through the vector parsing overload; ordinary
C-string command-line arguments cannot carry embedded NUL bytes.
To retain the historical behavior, define
TCLAP_ALLOW_NUL_TRUNCATION=1 before including any TCLAP headers.
The default is 0. Compatibility mode passes only the prefix
before the first NUL to the extractor; it does not accept ordinary trailing
junk such as 42junk. For CMake consumers:
target_compile_definitions(myapp PRIVATE TCLAP_ALLOW_NUL_TRUNCATION=1)
Use the same setting across every translation unit in the program, including
libraries that include TCLAP, because it changes header-defined template
behavior. StringLike values, including
std::string, preserve all bytes under either setting.
Check the result of the entire parse before using any argument values for
application work. Parsing is not transactional: an error may leave earlier
arguments changed, or even store a value that subsequently fails its
constraint. isSet() does not restore old values and
cannot substitute for checking the whole parse.
To parse again, call reset() and supply fresh input.
The vector overload expects the program name at element 0 and erases that
element. Reset restores parser/argument state, not the caller's input vector.
Combined switches may also modify characters in that vector.
By default the parser reports input errors and exits. For recovery in an
embedding application, use setExceptionHandling(false)
and catch ArgException around the entire parse.
With automatic help/version enabled, their visitors throw
ExitException; handle that requested exit separately
and stop normal application work. The following example disables those
visitors to focus on error recovery.
#include <tclap/CmdLine.h>
#include <iostream>
#include <string>
#include <vector>
int main() {
TCLAP::CmdLine cmd("reuse example", ' ', "1", false);
cmd.setExceptionHandling(false);
TCLAP::ValueArg<int> number("n", "number", "number", false, 0, "integer");
cmd.add(number);
std::vector<std::string> first{"prog", "-n", "7", "--bogus"};
try {
cmd.parse(first);
return 1; // This input should fail.
} catch (const TCLAP::ArgException &) {
// A failure may leave number changed. Do no application work here.
}
cmd.reset();
// Build new input, including the program name; do not reuse first.
std::vector<std::string> second{"prog", "-n", "2"};
try { cmd.parse(second); }
catch (const TCLAP::ArgException &) { return 2; }
std::cout << number.getValue() << '\n';
return 0;
}
Constraints check values explicitly supplied on the command line. An omitted
optional argument has isSet() equal to false, and its
default value is intentionally not checked against its constraint. The
application decides whether and how to use that default. For example, an
optional integer may default to 0 even if its allowed input values are 1 and 2.
A required argument must still be supplied: its default does not satisfy the
requirement. Read values only after the whole parse succeeds.
For example, one might wish to allow only integers greater than 0. In
this case, simply create a class that implements the
Constraint<int> interface and checks
whether the value parsed is greater than 0 (done in the
check() method) and create your
Arg with your new
Constraint.
TCLAP provides a simple way to constrain the
allowed values to a list of values. Simply create a
ValuesConstraint object with a
vector of values and add that to the
Arg.
When the value for the Arg is parsed, it is
checked against the list of values specified in the
ValuesConstraint. If the value is in the list
then it is accepted. If not, then an exception is thrown. Here is a
simple example:
vector<string> allowed;
allowed.push_back("homer");
allowed.push_back("marge");
allowed.push_back("bart");
allowed.push_back("lisa");
allowed.push_back("maggie");
ValuesConstraint<string> allowedVals( allowed );
ValueArg<string> nameArg("n","name","Name to print",true,"homer",&allowedVals);
cmd.add( nameArg );
When a ValuesConstraint is specified,
instead of a type description being specified in the
Arg, a
type description is created by concatenating the values in the
allowed list using operator<< for the specified type. The
help/usage for the Arg therefore lists the
allowable values. Because of this, you might want to keep the list
relatively small, however there is no limit on this.
Each Arg has a constructor that takes a
CmdLine object as an argument. Each
Arg then adds itself
to the CmdLine object. There is no difference
in how the Arg is handled between this method
and calling the add() method directly. Here
is an example:
// Create the command line.
CmdLine cmd("this is a message", '=', "0.99" );
// Note that the following args take the "cmd" object as arguments.
SwitchArg btest("B","existTestB", "exist Test B", cmd, false );
ValueArg<string> stest("s", "stringTest", "string test", true, "homer",
"string", cmd );
UnlabeledValueArg<string> utest("unTest1","unlabeled test one",
"default","string", cmd );
// NO add() calls!
// Parse the command line.
cmd.parse(argc,argv);
It is straightforward to change the output generated by
TCLAP. Either subclass the
StdOutput class and re-implement the methods you choose,
or write your own class that implements the
CmdLineOutput interface. Once you have done this,
then use the CmdLine setOutput
method to tell the CmdLine to use your new output
class. Here is a simple example:
class MyOutput : public StdOutput
{
public:
virtual void failure(CmdLineInterface& c, ArgException& e)
{
cerr << "My special failure message for: " << endl
<< e.what() << endl;
exit(1);
}
virtual void usage(CmdLineInterface& c)
{
cout << "my usage message:" << endl;
list<Arg*> args = c.getArgList();
for (ArgListIterator it = args.begin(); it != args.end(); it++)
cout << (*it)->longID()
<< " (" << (*it)->getDescription() << ")" << endl;
}
virtual void version(CmdLineInterface& c)
{
cout << "my version message: 0.1" << endl;
}
};
int main(int argc, char** argv)
{
CmdLine cmd("this is a message", ' ', "0.99" );
// set the output
MyOutput my;
cmd.setOutput( &my );
// proceed normally ...
See test4.cpp in the examples directory for the full
example. NOTE: if you supply your own Output object, we
will not delete it in the CmdLine destructor. This
could lead to a (very small) memory leak if you don't take care of the object
yourself. Also note that the failure method is
now responsible for exiting the application (assuming that is the desired
behavior).
Help and version information is useful for nearly all command line applications
and as such we generate flags that provide those options automatically.
However, there are situations when these flags are undesirable. For these
cases we've added we've added a forth parameter to the
CmdLine constructor. Making this boolean parameter
false will disable automatic help and version generation.
CmdLine cmd("this is a message", ' ', "0.99", false );
The automatically registered -- marker ends option
recognition. POSIX/GNU conventions treat following tokens as operands,
including tokens beginning with a dash; they do not mean that all following
input is discarded. TCLAP's ordinary unlabeled arguments consume those tokens
in their registered order. The marker itself is not an operand.
For example, with a switch -x and an unlabeled multi
argument for files, prog -x before -- -x after sets the switch once
and supplies the three operands before, -x and
after. The second -x is a file name, not
another switch occurrence. Required arguments are still checked after
--; the marker does not satisfy missing requirements.
TCLAP implements this through its separate ignoreable policy. Labeled arguments
are normally ignoreable, so they stop matching after the marker. Unmatched
remaining tokens are not reported as unknown-option errors. Unlabeled
arguments are normally not ignoreable and therefore continue consuming input.
Passing true for an unlabeled argument's constructor parameter
ignoreable makes it stop consuming after the marker as
well. This is a TCLAP policy choice, separate from the standard meaning of
ending option recognition.
By default, if TCLAP sees an argument that doesn't
match a specified Arg, it will produce an exception.
This strict handling provides some assurance that all input to a program
is controlled. However, there are times when
this strict handling of arguments might not be desirable.
TCLAP provides two alternatives. The first is to
add an UnlabeledMultiArg to the command line. If
this is done, all unmatched arguments will get added to this arg.
The second option is that
that TCLAP can simply ignore any unmatched
arguments on the command line. This is accomplished by calling the
ignoreUnmatched method with
true on the
CmdLine object that's been constructed.
// Define the command line object.
CmdLine cmd("Command description message", ' ', "0.9");
// Tell the command line to ignore any unmatched args.
cmd.ignoreUnmatched(true);
// Define a value argument and add it to the command line.
ValueArg<string> nameArg("n","name","Name to print",true,"homer","string");
cmd.add( nameArg );
// Parse the args.
cmd.parse( argc, argv );
Given the program above, if a user were to type:
% command -n Mike something to ignore
The program would succeed and the name ValueArg
would be populated with "Mike" but
the strings "something", "to", and "ignore" would simply be ignored by the
parser.
NOTE: If both ignoreUnmatched
is set to true and an UnlabeledMultiArg is added to
the command line, then the UnlabeledMultiArg will
"win" and all extra arguments will be added to it rather than be ignored.
Sometimes it's desirable to read integers formatted in decimal, hexadecimal,
and octal format. This is now possible by #defining the TCLAP_SETBASE_ZERO
directive. Simply define this directive in your code and integer arguments will be parsed
in each base.
#define TCLAP_SETBASE_ZERO 1
#include "tclap/CmdLine.h"
#include <iostream>
using namespace TCLAP;
using namespace std;
int main(int argc, char** argv)
{
try {
CmdLine cmd("this is a message", ' ', "0.99" );
ValueArg<int> itest("i", "intTest", "integer test", true, 5, "int");
cmd.add( itest );
//
// Parse the command line.
//
cmd.parse(argc,argv);
//
// Set variables
//
int _intTest = itest.getValue();
cout << "found int: " << _intTest << endl;
} catch ( ArgException& e )
{ cout << "ERROR: " << e.error() << " " << e.argId() << endl; }
}
The reason that this behavior is not the default behavior for TCLAP is that the use of
setbase(0) appears to be something of a side effect and is not necessarily how
setbase() is meant to be used. So while we're making this functionality
available, we're not turning it on by default for fear of bad things happening in different compilers.
If you know otherwise, please let us know.
The usual C++ types (int, long, bool, etc.) are supported by TCLAP out
of the box. As
long as operator>> and operator<< are supported, other types should work fine
too, you'll just need to specify the ArgTraits which
tells TCLAP how you expect the type to be handled.
For example, assume that you'd like to read one argument on the
command line in as a std::pair object. You need
to tell TCLAP whether to treat
std::pair as a String or Value (default).
StringLike means to treat the string on the command line as a string
and use it directly (by assignment operator), whereas ValueLike means
that a value object should be extracted from the string using
operator>>. For std::pair we'll choose
ValueLike. Here is an example of how to do this for int,double pair
(see test47.cpp):
#include <iostream>
#include <utility>
// We need to tell TCLAP how to parse our pair, we assume it will be
// given as two arguments separated by whitespace.
std::istream &operator>>(std::istream &is, std::pair<int, double> &p) {
return is >> p.first >> p.second;
}
// Make it easy to print values of our type.
std::ostream &operator<<(std::ostream &os, const std::pair<int, double> &p) {
return os << p.first << ' ' << p.second;
}
#include "tclap/CmdLine.h"
using namespace TCLAP;
// Our pair can now be used as any other type.
int main(int argc, char **argv) {
CmdLine cmd("test pair argument");
ValueArg<std::pair<int, double> > parg("p", "pair", "int,double pair",
true,
std::make_pair(0, 0.0),
"int,double",
cmd);
cmd.parse(argc, argv);
std::cout << parg.getValue() << std::endl;
}
Important: When specifying the argument on the command line it
needs to be given as a single argument, that is by quoting it. For
example, ./test30 -p "1 2.3".
If you do not want to provide operator>>, you can instead use
operator= by defining the type as
StringLike. A complete example is given in
test11.cpp, but the main difference is you need
to tell TCLAP to assign to the type using operator=. This is done by
defining it as StringLike as shown below:
namespace TCLAP {
template<>
struct ArgTraits<Vect3D> {
typedef StringLike ValueCategory;
};
}
It is traditional in Posix environments that the "-" and "--" strings are used to signify
the beginning of argument flags and long argument names. However, other environments,
namely Windows, use different strings. TCLAP allows you to
control which strings are used with #define directives. This allows
you to use different strings based on your operating environment. Here is an example:
//
// This illustrates how to change the flag and name start strings for
// Windows, otherwise the defaults are used.
//
// Note that these defines need to happen *before* tclap is included!
//
#ifdef WINDOWS
#define TCLAP_NAMESTARTSTRING "~~"
#define TCLAP_FLAGSTARTSTRING "/"
#endif
#include "tclap/CmdLine.h"
using namespace TCLAP;
using namespace std;
int main(int argc, char** argv)
{
// Everything else is identical!
...
For more information, look at the API Documentation and the examples included with the distribution.
Happy coding!