给 C++ 小工具添加命令行参数时,很容易从几个 argv 判断开始,逐渐写出一串处理短参数、默认值、类型转换和错误提示的代码。参数多起来以后,帮助信息也要跟着手动维护。
arg_parser 把这些常用操作整理成一个小型库:注册参数,调用 parse(),再通过 get<T>() 读取结果。项目只需要一个头文件,适合给文件处理工具、命令行程序和个人项目添加基础的参数解析能力。
项目地址:KAI-SHUNG/arg_parser。
有哪些功能?
- 单头文件、无第三方依赖:使用 C++17,把
arg_parser.hpp放进项目即可,不需要额外编译库文件。 - 三类参数:支持无值开关、带值选项和位置参数,也支持短别名。
- 参数配置与类型获取:支持默认值、必填参数、描述,以及
get<std::string>()、get<int>()等读取方式。 - 内置帮助输出:根据注册信息生成用法和参数说明,应用可以用它处理
-h、--help。 - Windows Unicode 输入:支持从
wmain接收 UTF-16 参数,并转换为 UTF-8。
例如,下面几种输入都可以解析:
|
|
如何接入项目?
可以先克隆仓库:
|
|
然后把 arg_parser.hpp 复制到自己的源码目录或头文件搜索目录,在代码中包含它:
|
|
编译器需要支持 C++17。下面的完整示例可以直接保存为 demo.cpp,与头文件放在同一目录。
一个完整可运行的例子
这个示例接收输入文件名、输出文件名、一个整数和一个布尔开关。它只打印解析结果,用来展示接口,不执行实际的文件处理。
|
|
在 Linux、macOS 等使用 main 的环境中,可以这样编译运行:
|
|
Windows 使用 MinGW 编译上述 wmain 版本时,需要加上 -municode:
|
|
输出如下:
|
|
没有传入参数时,会使用示例中配置的默认值:input.png、output.txt、80 和 false。这里没有启用 std::boolalpha,因此布尔值打印为 0 或 1。
仓库也提供了较短的 example.cpp,可以直接克隆后编译运行。
三类参数分别怎么用?
注册接口是:
|
|
name 是正式名称,alias 是可选别名,两者都不带前导 -。名称和别名不能与已经注册的参数冲突。默认类型是位置参数,返回的 Argument& 可以继续链式调用配置函数。
| 类型 | 注册示例 | 命令行输入 | 用途 |
|---|---|---|---|
Positional |
add_argument("input") |
photo.png |
按注册顺序接收位置参数 |
Option |
add_argument("output", "o", ArgType::Option) |
--output result.txt 或 -o=result.txt |
接收一个值 |
Flag |
add_argument("verbose", "v", ArgType::Flag) |
--verbose 或 -v |
表示开关,提供时保存为 "true" |
带值选项支持这四种形式:
|
|
位置参数默认也不是必填。需要用户明确提供时,要单独设置 set_required(true)。
默认值、必填参数与类型转换
默认值使用字符串配置,读取时再转换为目标类型。例如,完整示例已经为 count 配置了 .set_default("80"),解析后可以这样读取:
|
|
如果用户省略 count,get<int>("count") 会返回默认值 80。如果传入 --count=12abc,读取整数时会抛出异常,不会只取前面的 12。字符串读取会保留空格;例如 "my photo.png" 会作为一个完整的文件名返回。
对于必须显式传入的选项,可以在调用 parse() 前注册:
|
|
此时需要提供 --config settings.json。即使这个参数设置了默认值,也不能代替用户的显式输入。
get<bool>() 当前按字符串是否等于 "true" 返回结果。因此,开关参数通常搭配 .set_default("false") 使用;不要把它当作支持任意布尔字面量的转换器。
has() 和 get<T>() 有什么区别?
has() 判断的是“用户是否明确提供了这个参数”,默认值不算明确提供。它支持正式名称和别名,例如 has("output") 与 has("o")。
get<T>() 则读取参数值:用户提供了就读取输入,没提供就尝试默认值。读取时应使用正式名称,例如 get<std::string>("output"),不要使用别名 "o"。
两者配合,适合区分“用户主动设置”与“使用程序默认配置”:
|
|
这些读取操作都应放在 parse() 之后。
帮助信息不用单独维护
运行:
|
|
会得到上面完整示例生成的帮助信息:
|
|
参数名称、别名和描述都来自注册信息。set_program_name() 可以设置用法中的程序名,set_note() 可以在帮助末尾追加说明。
注意:注册一个叫 help 的参数不会自动显示帮助。应用需要在解析后检查它,再调用 help(),完整示例已经展示了这一流程。
Windows 中文参数怎么处理?
头文件在 Windows 上提供 parse(argc, wchar_t** argv) 重载,可以与 wmain 配合,把 UTF-16 参数转换为 UTF-8。对于中文文件名等非 ASCII 参数,这能保留输入内容,例如:
|
|
get<std::string>() 得到的是 UTF-8 字符串。后续如果把它交给文件操作接口,还需要确认该接口接受的编码;终端显示效果也取决于终端配置。
一些需要了解的边界
这个项目的接口集中在基础参数解析。使用时需要注意以下约定:
- 负数和以
-开头的选项值使用=:例如--count=-12、--output=-result.txt。--count -12会被视为缺少值。 - 以
-开头的位置参数使用--分隔:例如./demo -- -photo.png,分隔符后的内容按位置参数处理。 - 不支持短开关合并:用
-v -h,不要写成-vh。 - 位置参数仍按顺序传入:帮助输出目前会把
input列在Options中,但实际应写./demo photo.png,不能用--input=photo.png。 - 同一个开关或选项不能重复提供:例如
--output=a.txt -o=b.txt会被拒绝。 - 每个解析器实例只调用一次
parse():需要解析另一组输入时,新建实例。 - 必填检查先于应用的帮助处理:如果添加了必填参数,仅传
-h仍可能在parse()中触发缺少必填参数的异常。需要自行安排错误与帮助的展示流程;完整示例会在捕获异常后显示帮助。
未知参数、缺少选项值、重复输入和必填参数缺失会在解析时报告;数值转换错误会在调用 get<T>() 时报告。实际应用中,建议像完整示例一样捕获异常并给出错误提示。
如何运行项目测试?
仓库包含参数解析、别名、默认值、必填检查、类型转换、帮助输出和 Unicode 输入等测试。可以在仓库根目录编译运行:
|
|
Windows 下把输出文件名改成 test_arg_parser.exe,并运行 ./test_arg_parser.exe。测试程序使用普通 main,不需要 -municode。
项目地址与许可证
项目采用 MIT 许可证,完整源码、接口说明和示例都在仓库中:
如果你正在给一个 C++ 小工具添加命令行入口,可以从这个单头文件开始试用。欢迎通过 Issues 反馈使用问题,也欢迎提交改进。