Sharg 1.1.2-rc.1
The argument parser for bio-c++ tools.
Loading...
Searching...
No Matches
How to make your own validator

This HowTo guides you through implementing your own sharg::validator.

DifficultyEasy
Duration10 min
Prerequisite tutorials
Recommended reading

Motivation

To use a custom validator sharg::validator, the type must satisfy certain requirements (listed below). This tutorial shows you what requirements must be met and supplies you with a copy and paste source for your code.

sharg::validator

Remember the tutorial on Parsing command line arguments with Sharg ? Let's implement our own validator that checks if a numeric argument is an integral square (i.e. the user shall only be allowed to enter 0, 1, 4, 9...).

Understanding the requirements

In order to model the sharg::validator, your custom validator must provide the following:

  1. It needs to expose a value_type type member which identifies the type of variable the validator works on. Currently, the Sharg validators either have value_type double or std::string. Since the validator works on every type that has a common reference type to value_type, it enables a validator with value_type = double to work on all arithmetic values.
    Attention
    In order to be chainable, the validators need to share the same value_type!
  2. It has to be a functor, which basically means it must provide operator().
  3. It has to have a member function std::string get_help_page_message() const that returns a string that can be displayed on the help page.

Formally satisfying the requirements

You can check if your type models sharg::validator in the following way:

struct custom_validator
{
// ...
};
The concept for option validators passed to add_option/positional_option.
Definition validators.hpp:49

To formally satisfy the requirements, your functions do not need the correct behaviour, yet. Only the signatures need to be fully specified.

Assignment 3: Custom validator I

Implement enough of the above-mentioned struct custom_validator for it to model sharg::validator and pass the check. You can use an empty main()-function for now.
Solution

// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <sharg/parser.hpp>
struct custom_validator
{
using option_value_type = double; // used for all arithmetic types
void operator()(option_value_type const &) const
{
// add implementation later
}
std::string get_help_page_message() const
{
// add real implementation later
return "";
}
};
static_assert(sharg::validator<custom_validator>); // does not cause compile error
int main()
{}
Provides sharg::parser class.

Implementing the functionality

The above implementation is of course not yet useful. It should be usable with this main function:

int main(int argc, char ** argv)
{
sharg::parser myparser("Test-Parser", argc, argv);
int32_t variable{};
int16_t variable2{};
myparser.add_option(variable,
.description = "An int that is a square",
.validator = custom_validator{}}); // ← your validator is used!
myparser.add_option(variable2,
.description = "An int that is a square and within [0,20].",
.validator = custom_validator{}
| sharg::arithmetic_range_validator{0, 20}}); // ← now it's chained
try
{
myparser.parse(); // trigger command line parsing
}
catch (sharg::parser_error const & ext)
{
std::cout << ext.what() << '\n';
return -1;
}
std::cout << "Yeah!\n";
return 0;
}
A validator that checks whether a number is inside a given range.
Definition validators.hpp:79
Parser exception that is thrown whenever there is an error while parsing the command line arguments.
Definition exceptions.hpp:40
The Sharg command line parser.
Definition parser.hpp:154
Parser exception thrown when an argument could not be casted to the according type.
Definition exceptions.hpp:180
The concept for option validators passed to add_option/positional_option.
Definition validators.hpp:49
Provides sharg::parser class.
T pow(T... args)
T round(T... args)
T sqrt(T... args)
Option struct that is passed to the sharg::parser::add_option() function.
Definition config.hpp:43
char short_id
The short identifier for the option (e.g. 'a', making the option callable via -a).
Definition config.hpp:53
T what(T... args)

Try to think of the correct behaviour of this program.

It should print "Yeah!" for the arguments -i 0, -i 4, or -i 144 with -j 0 or -j 4.

It should fail for the arguments -i 3 with -j 144 or -j 3.

Assignment 4: Custom validator II

Implement your validator fully, i.e. make it throw sharg::validation_error if the number provided is not a square. Additionally, give a nice description for the help page.

Solution

#include <cmath>
struct custom_validator
{
using option_value_type = double; // used for all arithmetic types
void operator()(option_value_type const & val) const
{
if ((std::round(val) != val) || // not an integer
(std::pow(std::round(std::sqrt(val)), 2) != val)) // not a square
{
throw sharg::validation_error{"The provided number is not an arithmetic square."};
}
}
std::string get_help_page_message() const
{
return "Value must be the square of an integral number.";
}
};

You have now written your own type that is compatible with our constrained interfaces!

Hide me