cli11解析失败默认抛异常需try/catch捕获std::exception;字符串选项允空值多次出现,数值需std::optional才可选;子命令须显式parse();windows中文参数需cli11_parse_windows_main宏。

CLI11 解析失败时 std::runtime_error 抛出但没被捕获
CLI11 在解析失败(比如传了未知选项、缺参数、类型转换失败)时默认直接抛 std::runtime_error,不返回错误码。很多新手直接调 app.parse(argc, argv) 后就继续执行,结果一输错命令就 crash。
- 必须用
try/catch包住parse()调用,且 catchstd::exception&(CLI11 也抛std::logic_error等) - 不要只 catch
std::runtime_error—— 比如--port abc触发的是std::invalid_argument,也会被抛出 - catch 后建议调
app.exit(1)或打印app.help(),否则程序静默退出,用户不知道哪错了
try { app.parse(argc, argv); } catch (const std::exception& e) { std::cerr << e.what() << "nn"; app.exit(1); }
add_option 的 std::String 和 int 参数行为差异
CLI11 对不同类型的选项变量处理逻辑不同:字符串类选项默认支持“空值”和多次出现,数值类则严格校验格式与范围,这点容易误用。
-
add_option("-f,--file", filename)中filename是std::string:允许--file不带值(设为空串),也支持多次出现(最后赋值覆盖) -
add_option("-p,--port", port_num)中port_num是int:要求必须跟有效整数,--port单独写会报错;若需可选数值,得用std::optional<int></int>+->required(false) - 布尔选项别用
add_option,要用add_flag—— 否则--verbose true会被当字符串解析,不触发 bool 转换
子命令(subcommand)里忘记调 parse() 导致参数丢失
CLI11 的子命令不是自动激活的。即使你注册了 app.add_subcommand("build"),如果主命令解析完没显式调子命令的 parse(),子命令下的选项一个都收不到。
- 必须在检测到子命令被触发后,手动调它的
parse(),例如:if (build_cmd->parsed()) { build_cmd->parse(); } - 子命令的
parsed()返回true仅表示它被匹配到了(比如写了./app build),不代表它的参数已解析 - 常见坑:把子命令选项加在主
App上,而不是子命令对象上 —— 那些选项永远不会被识别
Windows 下中文路径/参数乱码(GetCommandLineW 未启用)
CLI11 默认用 argc/argv,在 Windows 控制台中,非 ASCII 字符(比如中文路径、含中文的 --input 文件.txt)会变成乱码或截断,根本进不到 parse() 阶段。
立即学习“C++免费学习笔记(深入)”;
- 必须在
main()开头调CLI11_PARSE_WINDOWS_MAIN宏(需定义UNICODE和链接shell32.lib) - 或者手动用
GetCommandLineW()+CommandLineToArgvW()构造宽字符 argv,再转 UTF-8 给 CLI11 —— 但宏更稳 - VS 项目要确认字符集设为“使用 Unicode 字符集”,否则
GetCommandLineW编译不过
CLI11 的链式调用看着简洁,但每个 -> 后的方法实际都在改内部状态;一旦漏掉 required(false)、check() 或 parse(),问题往往延迟到运行时才暴露,而且错误信息不指向具体哪行配置。