问题描述
我想编写一个程序来解析配置文件,并允许命令行覆盖那里写的内容。所以我可以有一个配置文件,上面写着:
[section1]
opt1=42
[section2]
opt2=17
然后,我可以运行以下命令:
./so --opt2=3
该程序将opt1
的值分别设置为42,opt2
和3。我使用以下程序进行尝试:
#include <fstream>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
int main(int argc,char *argv[]) {
po::options_description options1("section1");
options1.add_options()
("opt1",po::value<int>(),"Option 1");
po::options_description options2("section2");
options2.add_options()
("opt2","Option 2");
po::options_description options;
options.add(options1);
options.add(options2);
po::variables_map values;
po::store( po::command_line_parser( argc,argv ).options(options).run(),values );
std::ifstream iniFile( "options.ini" );
po::store(
parse_config_file( iniFile,options ),values );
}
这当然是行不通的。 Boost :: program_options希望将opt1
下的section1
称为section1.opt1
。但是,如果这样做,我的程序将很难在两个方面进行维护:
是否有一种无需手动完成工作的方法?
解决方法
最简单的解决方案是不使用这些部分。选项说明中的“节”与ini文件中的节之间可能会有一些混淆。
ini文件中的各节仅 引用以嵌入句点命名的选项:"section1.opt1"
。因此,您只需将配置文件写为:
opt1=42
# perhaps with a comment
opt2=17
#include <boost/program_options.hpp>
#include <fstream>
#include <iostream>
namespace po = boost::program_options;
int main(int argc,char* argv[]) {
po::options_description options;
options.add_options()
("opt1",po::value<int>(),"Option 1")
("section2.opt2","Option 2");
std::cout << options << "\n";
po::variables_map values;
po::store(po::parse_command_line(argc,argv,options),values);
std::ifstream iniFile("options.ini");
po::store(parse_config_file(iniFile,values);
auto report = [&values](char const* name) {
if (auto opt = values[name]; !opt.empty())
std::cout << name << ": " << opt.as<int>() << "\n";
};
report("opt1");
report("opt2");
report("section1.opt1");
report("section2.opt2");
}
打印
echo "opt1=42" >> options.ini; ./a.out --section2.opt2 99
--opt1 arg Option 1
--section2.opt2 arg Option 2
opt1: 42
section2.opt2: 99