Argument Class

Class Definition

template<class T>
class JSL::Argument : public JSL::ArgumentInterface

A class which allows arbitrary template parameters to be read in as command-line arguments or from a configuraiton file using a Name/Value pair system. Upon construction, the Value parameter takes the default value (if provided), until it is overriden by a successful argument/TriggerString match.

Public Functions

inline Argument()

Default constructor.

inline Argument(std::string trigger)

Constructor initialising the TriggerString. Value is set to uninitialised memory of the Template type.

Parameters:

trigger – The value of TriggerString, and the “name” of this parameter

inline Argument(T defaultValue, std::string trigger)

Constructor which initialises the TriggerString and Value members.

Parameters:
  • defaultValue – The initialisation value of Value - overridden if Parse() is called.

  • trigger – The value of TriggerString, and the “name” of this parameter

inline Argument(T defaultValue, std::string trigger, int argc, char *argv[])

Constructor which initialises as per Argument(T defaultValue, std::string trigger), but which also immediately calls ListParse() to check for assignment.

Parameters:
  • defaultValue – The initialisation value of Value - overridden if Parse() is called.

  • trigger – The value of TriggerString, and the “name” of this parameter

  • argc – The number of commandline arguments

  • argv[] – the command line list

inline Argument(T defaultValue, std::string trigger, std::string configFile, char configDelimiter)

Constructor which initialises as per Argument(T defaultValue, std::string trigger), but which also immediately calls Configure() to check for assignment.

Parameters:
  • defaultValue – The initialisation value of Value - overridden if Parse() is called.

  • trigger – The value of TriggerString, and the “name” of this parameter

  • configFile – The path to the file to open and parse for configuration data

  • configDelimiter – The delimiter used to separate Name/Value pairs in the cofiguration file

inline virtual void Configure(std::string configFile, char configDelimiter)

Iterate through a configuration file, extracting Name/Value pairs and calling Parse() in them. Each Name/Value pair should be on a new line in the file, and separated by the configDelimiter.

Parameters:
  • configFile – The path to the file to open and parse for configuration data

  • configDelimiter – The delimiter used to separate Name/Value pairs in the cofiguration file

inline virtual void ListParse(int argc, char *argv[])

Iterate through the provided commandline args, extracting Name/Value pairs and calling Parse() on them.

Parameters:
  • argc – The number of arguments passed to the program

  • argv[] – The argument list (argv[0] is assumed to be the the name of the program, and is ignored)

inline virtual void Parse(char *name, char *value)

Checks if the Name matches the TriggerString. For a successful match, Name must be prefaced by one more dash than found in TriggerString.

Parameters:
  • name – The name-string of the Name/Value pair

  • value – The value-string of the Name/Value pair.

inline operator T()

Allow the Argument object to be implicitly casted into the value of Value, and hence treated as an object of the templated type.

inline operator T() const

Annoying const version.

Public Members

T Value

The current value of the argument.

Private Functions

inline void CheckForInvalidTriggers()

Some Triggers are disallowed - they usually are protected names such as “help”, though other properties may trigger this funciton to throw an error.

inline virtual void StreamTo(std::stringstream &stream, std::string delimiter)
inline virtual void AssignValue(const char *value)

Virtual override for template-specific AssignValue calls. Most template types will require a custom handler to convert value into the chosen template type &#8212; some default ones are provided below.

inline void AssignValue(const char *value)

Override of the AssignValue() function for Argument<double> objects. Throws an error if the value is a non-integer, to prevent silent casting/truncation.

inline void AssignValue(const char *value)

Override of the AssignValue() function for Argument<double> objects.

inline void AssignValue(const char *value)

Override of the AssignValue() function for Argument<std::string> objects.

inline void AssignValue(const char *value)

Override of the AssignValue() function for Argument<bool> objects. Accepts only 0/1 as valid bool-strings.

Example Usage

Consider the following code

     #include <iostream>
     #include "JSL.h"
int main(int argc, char * argv[])
{

     //Explicit initialisation + parsing

     JSL::Argument<int> integer1(1,"integer1");
     integer1.ListParse(argc,argv);

     //Parsing at construction time
     JSL::Argument<int> integer2(5,"integer2",argc,argv);


     //Parsing from a configuration file
     std::string configFile = "config.txt";
     char delimiter = ",";
     JSL::Argument<double> double1(2.5,"double1",configFile, delimiter);
     JSL::Argument<std::string> string1("Goodbye","welcome-string",configFile,delimiter)


     //Print the output & Demonstrate the implicit casting ability of the "()" to work on almost everything except strings
     std::cout << (std::string)string1 << "\n";   // <- have to explicitly cast here because of char/string shenanigans. Everything else works.
     std::cout << integer1 << "\n";
     std::cout << integer2 << "\n";
     std::cout << double1 << "\n";

     std::cout << integer1 + integer2 << "\n";
     std::cout << integer1 + integer2 - double1 << "\n";
}

When called in the same directory as the configuration file config.txt

config.txt

integer1, 3
integer2, 23
double1, 101.1
welcome-string, Hello World!

The output is:

> ./argument
Hello World!
integer1 = 1
integer2 = 5
double1 = 101.1
integer1 + integer2 = 6
(integer2 - integer1) * double1 = 404.4

>./argument -integer1 3 -integer2 29 -double1 2.2
Hello World!
integer1 = 3
integer2 = 29
double1 = 101.1
integer1 + integer2 = 32
(integer2 - integer1) * double1 = 2628.6

The wrapper class ArgumentInterface also allows us to build heterogenous arrays which we can loop over to allow for easy & generalised initialisation:

JSL::Argument<int> integer1(1,"integer1");
JSL::Argument<int> integer2(2,"integer2");
JSL::Argument<double> double1(1.5,"double1");
JSL::Argument<double> double2(-2.2,"double2");
JSL::Argument<bool> bool1(true,"bool1");

std::vector<JSL::ArgumentInterface *> arguments = {&integer1, &integer2, &double1, &double2, &bool1};
for (int i = 0; i < arguments.size(); ++i)
{
        arguments[i]->ListParse(argc,argv);
}

Adding additional parameters merely requires initialising them and adding them to the arguments list.

Oddities & Notes of Caution

In the first example, note that although the -double1 2.2 pair was passed, the code still used the default value double1 = 101.1, as this parameter was only ever assigned to use the configuration file, rather than the command line agruments.

There is no centralised list of assigned TriggerStrings, so it is entirely possible for two different parameters to have the same name. Both will initialise to the same value. Equally, there is no checking if a parameter is assigned to multiple times (either from repeated arguments, or from both the command line and a configuration file). The command line/configuration files are read sequentially from top to bottom.