rfl::cli — Command-Line Argument Parser¶
Parse argc/argv into any reflectable struct via rfl::cli::read<T>(argc, argv).
Usage¶
#include <rfl/cli.hpp>
struct Config {
std::string host_name;
int port;
bool verbose;
std::optional<double> rate;
std::vector<std::string> tags;
};
int main(int argc, char* argv[]) {
const auto result = rfl::cli::read<Config>(argc, argv);
// ./app --host-name=localhost --port=8080 --verbose --tags=a,b,c
}
Field names undergo automatic snake_case -> kebab-case conversion:
host_name matches --host-name.
Positional arguments¶
Wrap a field with rfl::Positional<T> to accept it as a bare (non-flag) argument:
struct Config {
rfl::Positional<std::string> input_file;
rfl::Positional<std::string> output_file;
bool verbose;
};
// ./app input.txt output.txt --verbose
Positional arguments are matched in declaration order. They can also be
passed as named arguments: --input-file=input.txt.
The -- separator forces all subsequent tokens into positional:
./app --verbose -- --not-a-flag.txt
Short aliases¶
Wrap a field with rfl::Short<"x", T> to add a single-character alias:
struct Config {
rfl::Short<"p", int> port;
rfl::Short<"v", bool> verbose;
std::string host;
};
// ./app -p 8080 -v --host=localhost
// ./app -p=8080 -v --host=localhost
// ./app --port=8080 --verbose --host=localhost (long names still work)
Short bool flags do not consume the next token as a value — -v somefile
treats somefile as a positional argument, not as the value of -v.
To explicitly set a bool short flag, use = syntax: -v=true, -v=false.
Combining Positional and Short¶
Positional and Short can be used together in the same struct, but
cannot be nested (Positional<Short<...>> is a compile-time error):
struct Config {
rfl::Positional<std::string> input_file;
rfl::Short<"o", std::string> output_dir;
rfl::Short<"v", bool> verbose;
int count;
};
// ./app data.csv -o /tmp/out -v --count=10
Supported types¶
| Type | CLI format | Notes |
|---|---|---|
std::string |
--key=value |
|
int, long, ... |
--key=42 |
|
float, double |
--key=1.5 |
|
bool |
--flag or --flag=true |
No = implies true |
enum |
--key=value_name |
Via rfl::string_to_enum |
std::optional<T> |
omit for nullopt |
|
std::vector<T> |
--key=a,b,c |
Comma-separated; empty elements skipped |
| Nested struct | --parent.child=val |
Dot-separated path |
rfl::Flatten<T> |
fields inlined | No prefix needed |
rfl::Rename<"x", T> |
--x=val |
Bypasses kebab conversion |
rfl::Positional<T> |
bare token | Matched in declaration order |
rfl::Short<"x", T> |
-x value or -x=value |
Single-character alias |
Architecture¶
Parsing proceeds in three stages:
parse_argv— categorizes raw tokens intonamed,short_args, andpositionalbuckets (ParsedArgsstruct). No type information needed.resolve_args— uses compile-time metadata from the target struct to map short aliases to long names, reclaim values from bool short flags, and merge positional arguments. Produces a flatmap<string, string>.Reader— implements reflect-cpp'sIsReaderconcept by presenting virtual tree nodes over the flat map. Each node is a{map*, path}pair — no data copying, just prefix-based lookup vialower_bound.
Files¶
include/rfl/cli/read.hpp— public APIinclude/rfl/cli/Reader.hpp— Reader +parse_valueoverloadsinclude/rfl/cli/Parser.hpp— Parser type aliasinclude/rfl/cli/parse_argv.hpp—argv->ParsedArgsinclude/rfl/cli/resolve_args.hpp—ParsedArgs->map<string, string>include/rfl/cli.hpp— aggregator headerinclude/rfl/SnakeCaseToKebabCase.hpp— processorinclude/rfl/Positional.hpp—Positional<T>wrapperinclude/rfl/Short.hpp—Short<"x", T>wrapper