使用带有boost::program_options的多个源时,请使用最后一个存储值,而不是第一个存储值
Use the last rather than the first stored value when using multiple sources with boost::program_options
我的目标是在一个或多个INI文件中保留大部分时间不变的配置值,并从命令行读取其余参数。我正在使用boost::program_options来实现这一点。
基本上,
options_description options;
variables_map vm;
ifstream ifs("config.ini");
store(parse_config_file(ifs, options), vm);
// !!! Does not overwrite values from config.ini
store(command_line_parser(argc, argv).options(options).run(), vm);
只要INI和命令行中提供的参数不重叠,这种方法就可以很好地工作。如果它们重叠,所需的逻辑行为是命令行中的参数覆盖以前从INI文件中读取的任何内容。不过,这并不起作用,因为Boost的默认行为是使用第一个遇到的值,然后忽略任何其他值。
你有什么办法绕过这个限制吗?
我正在做的一个完整的工作示例:
#include <iostream>
#include <fstream>
#include <vector>
#include <boost/program_options.hpp>
using namespace std;
using namespace boost::program_options;
// Parsed values will be stored in these
std::vector<std::string> inputFiles;
int numThreads;
bool enableX;
void parseOptions(const int argc, const char* argv[])
{
//
// Define our config parameters
//
options_description basicOptions("Main options");
basicOptions.add_options()
("help,h", "Show full help.")
("version,V", "Show version.")
("config,c",
value<vector<string>>()->multitoken()->composing(),
"Path of a configuration INI file. Can be used repeatedly.n"
"The available config parameters are listed in the full help info."
)
("inputFile,i",
value<vector<string>>()->multitoken()->composing()->required(),
"Input file(s). Can be used repeatedly."
);
options_description configOptions("Configuration");
configOptions.add(basicOptions);
configOptions.add_options()
("numThreads",
value<>(&numThreads)->default_value(1),
"Number of processing threads."
)
// ... snip ...
("enableX",
value<>(&enableX)->default_value(true),
"Whether to enable X."
);
//
// Parse
//
variables_map vm;
// Parse the minimal set of command line arguments first
parsed_options parsedCL = command_line_parser(argc, argv).
options(basicOptions).allow_unregistered().run();
store(parsedCL, vm);
// Load configuration from INI files
if (vm.count("config"))
{
for (int i = 0; i < vm["config"].as<vector<string>>().size(); i++)
{
ifstream ifs(vm["config"].as<vector<string>>()[i].c_str());
store(parse_config_file(ifs, configOptions), vm);
}
}
// Parse and store the remaining command line arguments
// !!! store() does not overwrite existing values !!!
store(command_line_parser(
collect_unrecognized(parsedCL.options, include_positional)
).options(configOptions).run(), vm);
// Finally, check that that the provided input is valid
notify(vm);
}
int main(const int argc, const char* argv[])
{
try
{
parseOptions(argc, argv);
cout << "enableX: " << enableX << endl;
}
catch (exception e)
{
cerr << e.what() << endl;
}
return 0;
}
如果使用--config config.ini --enableX false
运行上述程序,config.ini的内容为
numThreads = 4
enableX = true
它从命令行输出"enableX:1",而不是"enableX:0"——所需的值。
在一次破解尝试中,我尝试在存储任何新参数之前,简单地从variable_map
中删除冲突的参数:
void store_with_overwrite(const parsed_options& parsed, variables_map& vm)
{
for (const option& option : parsed.options)
{
auto it = vm.find(option.string_key);
if (it != vm.end())
{
vm.erase(it);
}
}
store(parsed, vm);
}
这不起作用,因为Boost也将第一个遇到的值存储在私有m_final
成员变量中,即使参数已从映射中删除,也会使用该变量。
我现在能想到的唯一解决方案是首先解析命令行参数,然后在store()
处理INI文件之前,从INI文件中删除parsed_options
中任何冲突的值。缺点是,我必须手动跟踪使用multitoken()
和composing()
的选项,这些选项不能删除。
必须有更好的方法。你有什么建议吗?
由于第一个存储的值是最后一个保持不变的值,这也是我想要的命令行值,因此解决方案实际上很简单:首先从命令行解析和存储所有内容。
通常,将来自不同来源的值以与您希望它们相互"覆盖"的顺序相反的顺序存储。
variables_map vm;
// Parse the command line arguments first
parsed_options parsedCL = command_line_parser(argc, argv).
options(configOptions).run();
store(parsedCL, vm);
// Load configuration from INI files
if (vm.count("config"))
{
for (int i = 0; i < vm["config"].as<vector<string>>().size(); i++)
{
ifstream ifs(vm["config"].as<vector<string>>()[i].c_str());
store(parse_config_file(ifs, configOptions), vm);
}
}
// Finally, check that that the provided input is valid
notify(vm);
相关文章:
- 如果不是多个语句,请使用 if 语句
- Clang-CL 警告 strnicmp 已弃用,请使用 ISO C 并C++符合标准的名称_strnicmp
- 如果输入缓冲区不为空,请使用getchar.()检测Ctrl+d
- 如果 (QString.contains()) 不能正常工作,请使用 temp bool 变量进行更正
- 如果两个字符串是字谜,请使用unordered_map确定它们
- 我如何在C 中的向量中存储和使用不同的类
- 使用SEND()之前,请使用Select()检查套接字
- 在编写平台依赖代码时,请使用constexpr代替宏
- 如果元组足够大,请使用sfinae启用方法
- 使用带有boost::program_options的多个源时,请使用最后一个存储值,而不是第一个存储值
- 特征错误:请使用密码保护您的最小值
- 要在不使用cout的情况下打印某些内容,请使用printf或puts()
- 在指定模板类之前,请使用模板类
- 在Fedora 20 x86_64上编译32位Linux应用程序时,请使用SNDFILE库
- 如何在类的成员中存储函数?(使用函数作为回调)
- 将shared_ptr与通用注册表或共享对象存储一起使用.或不
- C++类型擦除,请使用 std::function 捕获单个类的多个方法
- 对于几乎相似的内容,请使用qml文件
- 如何读取一个不完整的表单字段,请使用C++
- 存储可以使用不同派生类型初始化的基类型成员变量时,请避免使用new