Simple, extensible, header-only C++17 argument parser released into the public domain.
Other argument parsers are:
- bloated
- non-extensible
- not modern
- complicated
GCC 7.0 or Clang 4.0.0 at a minimum. This library makes extensive use of optional
, nullopt
, and string_view
.
flags::args
exposes seven methods:
std::optional<T> get(const std::string_view& key) const
Attempts to parse the given key on the command-line. If the string is malformed or the argument was not passed, returns nullopt
. Otherwise, returns the parsed type as an optional.
T get(const std::string_view& key, T&& default_value) const
Functions the same as get
, except if the value is malformed or the key was not provided, returns default_value
. Otherwise, returns the parsed type.
std::vector<std::optional<T>> get_multiple(const std::string_view& option) const
Get all values passed for an option. If no value is specified (--foo --bar
) or the value is malformed, nullopt
will be used. Values will be in the order they were passed.
std::vector<T> get_multiple(const std::string_view& option, T&& default_value) const
Functions the same as get_multiple
, except if the value is malformed or no value is provided, default_value
will be used.
std::optional<T> get(size_t positional_index) const
Get an argument from the positional arguments at a specified index. If the value is malformed or the index is invalid, nullopt
is returned.
T get(size_t positional_index, T&& default_value) const
Functions the same as positional get
, except if the value is malformed or the index is invalid, returns default_value
. Otherwise, returns the parsed type.
const std::vector<std::string_view>& positional() const
Returns all of the positional arguments from argv in order.
Just include flags.h
from the include
directory into your project.
Flags can be built and installed using [CMake], e.g.
$ mkdir build
$ cd build
$ cmake ..
$ make
$ make install
The above will install Flags into the standard installation path on a UNIX
system, e.g. /usr/local/include/
. To change the installation path, use:
$ cmake .. -DCMAKE_INSTALL_PREFIX=../install
in the above.
Installation creates a flags-config.cmake
which allows CMake
projects to find Flags using find_package
:
find_package(flags)
This exports the flags
target which can be linked against any other
target. Linking against flags
automatically sets the include
directories and required flags for C++17 or later. For example:
add_executable(myexe mysources...)
target_link_libraries(myexe PRIVATE flags)
The Flags can also be added as a dependency with add_subdirectory
:
add_subdirectory(path/to/flags)
This also exports the flags
target which can be linked against any
other target just as with the installation case.
#include "flags.h" // #include <flags.h> for cmake
#include <iostream>
int main(int argc, char** argv) {
const flags::args args(argc, argv);
const auto count = args.get<int>("count");
if (!count) {
std::cerr << "No count supplied. :(\n";
return 1;
}
std::cout << "That's " << *count << " incredible, colossal credits!\n";
if (args.get<bool>("laugh", false)) {
std::cout << "Ha ha ha ha!\n";
}
return 0;
}
$ ./program
> No count supplied. :(
$ ./program --count=5 --laugh
> That's 5 incredible, colossal credits!
> Ha ha ha ha!
#include "flags.h" // #include <flags.h> for cmake
#include <iostream>
#include <string>
int main(int argc, char** argv) {
const flags::args args(argc, argv);
const auto& files = args.positional();
const auto verbose = args.get<bool>("verbose", false);
if (verbose) {
std::cout << "I'm a verbose program! I'll be reading the following files:\n";
for (const auto& file : files) {
std::cout << "* " << file << '\n';
}
}
// read files(files);
return 0;
}
$ ./program /tmp/one /tmp/two /tmp/three --verbose
> I'm a verbose program! I'll be reading the following files:
> * /tmp/one
> * /tmp/two
> * /tmp/three
$ ./program /tmp/one /tmp/two /tmp/three --noverbose
>%
flags
simply uses the istream
operator to parse values from argv
. To extend the parser to support your own types, just supply an overloaded >>
.
struct Date {
int day;
int month;
int year;
};
// Custom parsing code.
std::istream& operator>>(std::istream& stream, Date& date) {
return stream >> date.day >> date.month >> date.year;
}
int main(int argc, char** argv) {
const flags::args args(argc, argv);
if (const auto date = args.get<Date>("date")) {
// Output %Y/%m/%d if a date was provided.
std::cout << date->year << ":" << date->month << ":" << date->day << '\n';
return 0;
}
// Sad face if no date was provided or if the input was malformed.
std::cerr << ":(\n";
return 1;
}
$ ./program --date="10 11 2016"
> 2016:11:10
$ ./program
> :(
flags
's primary goal is to be simple to use for both the user and programmer.
A key can have any number of preceding -
s, but must have more than 0.
The following are valid keys:
-key
--key
-------------key
A value can be assigned to a key in one of two ways:
$ ./program --key=value
$ ./program --key value
booleans are a special case. The following values make an argument considered false
-y when parsed as a bool:
f
false
n
no
0
If none of these conditions are met, the bool is considered true
.
flags uses both bfg9000 and mettle for unit-testing. After installing both bfg9000
and mettle
, run the following commands to kick off the tests:
9k build/
cd build
ninja test
Contributions of any variety are greatly appreciated. All code is passed through clang-format
using the Google style.