百科.dev
全部条目AI 编程趋势榜开源项目技术资讯提交条目
登录
< 返回工具列表
C

clipp

> 开发工具
开源

易于使用、功能强大且表达力强的命令行参数解析,适用于现代 C++、单个头文件、使用说明和文档生成

1.3K stars0 点赞0 次浏览
访问官网GitHub

工具介绍

易于使用、功能强大且表达力强的命令行参数解析,适用于现代 C++、单个头文件、使用说明和文档生成

clipp - command line interfaces for modern C++

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

  • options, options+value(s), positional values, positional commands, nested alternatives, decision trees, joinable flags, custom value filters, ...

  • documentation generation (usage lines, man pages); error handling

  • lots of examples; large set of tests

  • Quick Reference Table

  • Overview (short examples)

  • Detailed Examples

  • Why yet another library for parsing command line arguments? / Design goals

  • Requirements / Compilers

Quick Intro

Simple Use Case — Simple Setup!

Consider this command line interface:

SYNOPSIS
    convert  [-r] [-o ] [-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.

…

This CLI has three alternative commands (make, find, help), some positional value-arguments (, ) of which one is repeatable, a required flag with value-argument (-dict ), an option with value-argument (-o ), 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:

…

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 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 ls;
auto cli = (
    //option with required value
    option("-n", "--repeat") & value("times", n),

    //required flag with optional value
    required("--file") & opt_value("name", s),
    
    //option with exactly two values
    option("-p", "--pos") & value("x") & value("y"),

    //same as before                   v            v
    in_sequence( option("-p", "--pos") , value("x") , value("y") ),
    
    //option with at least one value (and optionally more)
    option("-l") & values("lines", ls)
);
Filtering Value Parameters

Value parameters use a filter function to test if they are allowed to match an argument string. The default filter match::nonempty that is used by value, values, opt_value and opt_values will match any non-empty argument string. You can either supply other filter functions/function objects as first argument of value, values, etc. or use one of these built-in shorthand factory functions covering the most common cases:

string name; double r = 0.0; int n = 0;
auto cli = (
    value("user", name),   // matches any non-empty string
    word("user", name),    // matches any non-empty alphanumeric string
    number("ratio", r),    // matches string representations of numbers
    integer("times", n)    // matches string representations of integers
);

Analogous to value, opt_value, etc. there are also functions for words, opt_word, etc.

Value Parameters With Custom Filters
auto is_char = [](const string& arg) { return arg.size() == 1 && std::isalpha(arg[0]); };

char c = ' ';
                             // matches       required  positional  repeatable
value(is_char, "c", c);      // one character  yes       yes         no

Groups

  • group mutually compatible parameters with parentheses and commas:

    auto cli = ( option("-a"), option("-b"), option("-c") );
    
  • group mutually exclusive parameters as alternatives using operator | or one_of:

    auto cli1 = ( value("input_file") | command("list") | command("flush") );
    
    auto cli2 = one_of( value("input_file") , command("list") , command("flush") );
    
  • group parameters so that they must be matched in sequence using operator & or in_sequence:

    double x = 0, y = 0, z = 0;
    auto cli1 = ( option("-pos") & value("X",x) & value("Y",y) & value("Z",z) );
    
    auto cli2 = in_sequence( option("-pos") , value("X",x) , value("Y",y) , value("Z",z) );
    

    Note that surrounding groups are not affected by this, so that -a and -b can be matched in any order while -b and the value X must match in sequence:

    bool a = false, b = false; int x = 0;
    auto cli = (  option("-a").set(a),  option("-b").set(b) & value("X",x)  );
    
  • groups can be nested and combined to form arbitrarily complex interfaces (see here and here):

    auto cli = ( command("push") | ( command("pull"), option("-f", "--force") )  );
    
  • groups can be repeatable as well:

    auto cli1 = repeatable( command("flip") | command("flop") );
    
  • force common prefixes on a group of flags:

    int x = 0;
    auto cli1 = with_prefix("-", option("a"), option("b") & value("x",x), ... );
                              // =>     -a           -b     ^unaffected^
    
    auto cli2 = with_prefix_short_long("-", "--", option("a", "all"), option("b"), ... );
                                                   // => -a  --all           -b
    
  • force common suffixes on a group of flags:

    int x = 0;
    auto cli1 = with_suffix("=", option("a") & value("x",x), ... );
                              // =>      a=    ^unaffected^
    
    auto cli2 = with_suffix_short_long(":", ":=", option("a", "all"), option("b"), ... );
                                                   // =>  a:   all:=          b:
    
  • make a group of flags joinable:

    auto cli1 = joinable( option("-a"), option("-b"));  //will match "-a", "-b", "-ab", "-ba"
    
    //works also with arbitrary common prefixes:
    auto cli2 = joinable( option("--xA0"), option("--xB1"));  //will also match "--xA0B1" or "--xB1A0"
    

Interfacing With Your Code

The easiest way to connect the command line interface to the rest of your code is to bind object values or function (object) calls to parameters (see also here):

bool b = false; int i = 5; int m = 0; string x; ifstream fs;
auto cli = ( 
    option("-b").set(b),                      // "-b" detected -> set b to true
    option("-m").set(m,2),                    // "-m" detected -> set m to 2
    option("-x") & value("X", x),             // set x's value from arg string 
    option("-i") & opt_value("i", i),         // set i's value from arg string  
    option("-v").call( []{ cout  " 
clipp::parameter
documented_value(const std::string& name, Target& tgt, const std::string& docstr) {
    using std::to_string;
    return clipp::value(name,tgt).doc(docstr + "(default: " + to_string(tgt) + ")");
}
//value that only matches strings without prefix '-'
template
clipp::parameter
nodash_value(std::string label, Target&& tgt, Targets&&... tgts) {
    return clipp::value(clipp::match::prefix_not{"-"}, std::move(label), 
               std::forward(tgt), std::forward(tgts)...);
}

…

man
SYNOPSIS
       switch [-a] [-b] [-c] [--hi]

OPTIONS
       -a          activates a
       -b          activates b
       -c, --noc   deactivates c
       --hi        says hi
bool a = false, b = false, c = true; //target variables

auto cli = ( 
    option("-a").set(a)                  % "activates a",
    option("-b").set(b)                  % "activates b",
    option("-c", "--noc").set(c,false)   % "deactivates c",
    option("--hi")([]{cout >``` and ```operator > b,             
    option("-c", "--noc") % "deactivates c" >> set(c,false),
    option("--hi")        % "says hi"       >> []{cout > b,             
    option("-c", "--noc") % "deactivates c" >> set(c,false),
    option("--hi")        % "says hi"       >> []{cout > b,
    "deactivates c" % option("-c", "--noc") >> set(c,false),
    "says hi"       % option("--hi")        >> []{cout >``` which means that you either have to keep the docstrings closer to the command line parameters than the actions or use parentheses.

You should also have a look at [actions](#actions) for more details.

#### Step-by-step configuration of parameters:
```cpp
int n = 1;

auto optN = parameter{"-n", "-N", "--iterations", "--repeats"}.required(true);

auto valN = parameter{match::any}
    .label("times")
    .set(n)
    .call([](string s) { if(!str::represents_number(s)) throw runtime_error{"invalid value for 'times'"}; })
    .if_missing([]{ cout  [-s]
   
OPTIONS
        infile        input filename
        outfile       output filename
        -s, --split   split files
string ifile, ofile;
bool split = false; 
auto cli = (
    value("infile", ifile)             % "input filename",
    value("outfile", ofile)            % "output filename",
    option("-s", "--split").set(split) % "split files" );

Alternative Value Mappi

Issues· 0 开放

查看全部 Issues在 GitHub 打开

暂无开放 Issues,或尚未同步最近议题。

> 标签

C++argsargument-parserargument-parsingargv

暂无评论,来聊聊你的看法吧

> 工具信息

发布日期2026年8月1日
最后更新2026年9月17日
分类开发工具
定价开源

> 相关工具

V
VS Code
流行的开源代码编辑器
G
Git
分布式版本控制系统
V
Vite
下一代前端构建工具