SkillAgentSearch skills...

Clipp

easy to use, powerful & expressive command line argument parsing for modern C++ / single header / usage & doc generation

Install / Use

/learn @muellan/Clipp

README

clipp - command line interfaces for modern C++

Linux build status MSVC build status

Easy to use, powerful and expressive command line argument handling for C++11/14/17 contained in a single header file.

Quick Intro

Simple Use Case — Simple Setup!

Consider this command line interface:

SYNOPSIS
    convert <input file> [-r] [-o <output format>] [-utf16]

OPTIONS
    -r, --recursive  convert files recursively
    -utf16           use UTF-16 encoding

Here is the code that defines the positional value input file and the three options -r, -o and -utf16. If parsing fails, the above default man page-like snippet will be printed to stdout.

#include <iostream>
#include "clipp.h"
using namespace clipp; using std::cout; using std::string;

int main(int argc, char* argv[]) { 
    bool rec = false, utf16 = false;
    string infile = "", fmt = "csv";

    auto cli = (
        value("input file", infile),
        option("-r", "--recursive").set(rec).doc("convert files recursively"),
        option("-o") & value("output format", fmt),
        option("-utf16").set(utf16).doc("use UTF-16 encoding")
    );

    if(!parse(argc, argv, cli)) cout << make_man_page(cli, argv[0]);
    // ...
}

A More Complex Example:

SYNOPSIS
    finder make <wordfile> -dict <dictionary> [--progress] [-v]
    finder find <infile>... -dict <dictionary> [-o <outfile>] [-split|-nosplit] [-v] 
    finder help [-v]

OPTIONS
    --progress, -p           show progress                       
    -o, --output <outfile>   write to file instead of stdout
    -split, -nosplit         (do not) split output
    -v, --version            show version

This CLI has three alternative commands (make, find, help), some positional value-arguments (<wordfile>, <infile>) of which one is repeatable, a required flag with value-argument (-dict <dictionary>), an option with value-argument (-o <outfile>), one option with two alternatives (-split, -nosplit) and two conventional options (-v, --progress).

Here is the code that defines the interface, generates the man page snippet above and handles the parsing result:

using namespace clipp; using std::cout; using std::string;

//variables storing the parsing result; initialized with their default values
enum class mode {make, find, help};
mode selected = mode::help;
std::vector<string> input;
string dict, out;
bool split = false, progr = false;

auto dictionary = required("-dict") & value("dictionary", dict);

auto makeMode = (
    command("make").set(selected,mode::make),
    values("wordfile", input),
    dictionary,
    option("--progress", "-p").set(progr) % "show progress" );

auto findMode = (
    command("find").set(selected,mode::find),
    values("infile", input),
    dictionary,
    (option("-o", "--output") & value("outfile", out)) % "write to file instead of stdout",
    ( option("-split"  ).set(split,true) |
      option("-nosplit").set(split,false) ) % "(do not) split output" );

auto cli = (
    (makeMode | findMode | command("help").set(selected,mode::help) ),
    option("-v", "--version").call([]{cout << "version 1.0\n\n";}).doc("show version")  );

if(parse(argc, argv, cli)) {
    switch(selected) {
        case mode::make: /* ... */ break;
        case mode::find: /* ... */ break;
        case mode::help: cout << make_man_page(cli, "finder"); break;
    }
} else {
     cout << usage_lines(cli, "finder") << '\n';
}

Quick Reference

Below are a few examples that should give you an idea for how clipp works. Consider this basic setup with a few variables that we want to set using command line arguments:

int main(int argc, char* argv[]) { 
    using namespace clipp;

    // define some variables
    bool a = false, b = false;
    int n = 0, k = 0;
    double x = 0.0, y = 0.0;
    std::vector<int> ids;

    auto cli = ( /* CODE DEFINING COMMAND LINE INTERFACE GOES HERE */ );

    parse(argc, argv, cli);    //excludes argv[0]

    std::cout << usage_lines(cli, "exe") << '\n';
}

| Interface (usage_lines) | Code (content of cli parentheses ) | -------------------------- | ------------------------------------ | exe [-a] | option("-a", "--all").set(a) | exe [--all] | option("--all", "-a", "--ALL").set(a) | exe [-a] [-b] | option("-a").set(a), option("-b").set(b) | exe -a | required("-a").set(a) | exe [-a] -b | option("-a").set(a), required("-b").set(b) | exe [-n <times>] | option("-n", "--iter") & value("times", n) | exe [-n [<times>]] | option("-n", "--iter") & opt_value("times", n) | exe -n <times> | required("-n", "--iter") & value("times", n) | exe -n [<times>] | required("-n", "--iter") & opt_value("times", n) | exe [-c <x> <y>] | option("-c") & value("x", x) & value("y", y) | exe -c <x> <y> | required("-c") & value("x", x) & value("y", y) | exe -c <x> [<y>] | required("-c") & value("x", x) & opt_value("y", y) | exe [-l <lines>...] | option("-l") & values("lines", ids) | exe [-l [<lines>...]] | option("-l") & opt_values("lines", ids) | exe [-l <lines>]... | repeatable( option("-l") & value("lines", ids) ) | exe -l <lines>... | required("-l") & values("lines", ids) | exe -l [<lines>...] | required("-l") & opt_values("lines", ids) | exe (-l <lines>)... | repeatable( required("-l") & value("lines", ids) ) | exe fetch [-a] | command("fetch").set(k,1), option("-a").set(a) | exe init \| fetch [-a] | command("init").set(k,0) \| (command("fetch").set(k,1), option("-a").set(a)) | exe [-a\|-b] | option("-a").set(a) \| option("-b").set(b) | exe [-m a\|b] | option("-m") & (required("a").set(a) \| required("b").set(b))

Overview

See the examples section for detailed explanations of each topic.

Namespace qualifiers are omitted from all examples for better readability. All entities are defined in namespace clipp.

Basic Setup

int main(int argc, char* argv[]) { 
    using namespace clipp;

    auto cli = ( /* CODE DEFINING COMMAND LINE INTERFACE GOES HERE */ );
    parse(argc, argv, cli);    //excludes argv[0]

    //if you want to include argv[0]
    //parse(argv, argv+argc, cli);
}

There are two kinds of building blocks for command line interfaces: parameters and groups. Convieniently named factory functions produce parameters or groups with the desired settings applied.

Parameters (flag strings, commands, positional values, required flags, repeatable parameters)

bool a = false, f = false;
string s; vector<string> vs;
auto cli = (                             // matches  required  positional  repeatable
    command("push"),                     // exactly      yes       yes         no
    required("-f", "--file").set(f),     // exactly      yes       no          no
    required("-a", "--all", "-A").set(a),  // exactly      no        no          no
                                                  
    value("file", s),                    // any arg      yes       yes         no
    values("file", vs),                  // any arg      yes       yes         yes
    opt_value("file", s),                // any arg      no        yes         no
    opt_values("file", vs),              // any arg      no        yes         yes
    
    //"catch all" parameter - useful for error handling
    any_other(vs),                       // any arg      no        no          yes
    //catches arguments that fulfill a predicate and aren't matched by other parameters
    any(predicate, vs)                   // predicate    no        no          yes
);

The functions above are convenience factories:

bool f = true; string s;
auto v1 = values("file", s);
// is equivalent to:
auto v2 = parameter{match::nonempty}.label("file").blocking(true).repeatable(true).set(s);

auto r1 = required("-f", "--file").set(f);
// is equivalent to:
auto r2 = parameter{"-f", "--file"}.required(true).set(f);
  • a required parameter has to match at least one command line argument
  • a repeatable parameter can match any number of arguments
  • non-positional (=non-blocking) parameters can match arguments in any order
  • a positional (blocking) parameter defines a "stop point", i.e., until it matches all parameters following it are not allowed to match; once it matched, all parameters preceding it (wihtin the current group) will become unreachable
Flags + Values

If you want parameters to be matched in sequence, you can tie them together using either operator & or the grouping function in_sequence:

int n = 1; string s; vector<int> ls;
auto cli = (
    //option with required value
    option("-n", "--repeat") & value("times", n),

    //required flag w
View on GitHub
GitHub Stars1.3k
CategoryDevelopment
Updated6h ago
Forks156

Languages

C++

Security Score

100/100

Audited on Mar 28, 2026

No findings