[C++Boost]程序参数项解析库Program_options使用指南
介绍
程序参数项(program options)是一系列name=value对,program_options 允许程序开发者获得通过命令行(command line)和配置文件(config file)获取这些参数项。
为什么需要这样一个库?为什么比你手工写代码分解命令行参数要好?
- 使用更容易。定义参数处理的语法简单,库自身很小。像转换参数值到指定的类型和保存参数值到变量的事情都是自动处理。
- 错误报告更友好。可报告错误的命令行参数。另外这个库能自动生成使用帮助,避免手工更新使用帮助导致的不一致。
- 参数能从不同地方读取。当命令行参数不能满足要求,需要改用配置文件或环境变量。
这些功能都能支持,代码改动很小。
使用指南
在本节,我们从最简单的例子开始,学习program_options库的通常用法。下面的例子仅仅是代码片断,完整例子在“BOOST_ROOT/libs/program_options/example”目录里。对所有例子,假定都在如下名字空间中:
namespace po = boost::program_options;
快速入门
第一个例子尽可能简单:仅仅包含两个参数项。代码如下(完整代码见“example/first.cpp”):
// Declare the supported options.
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
("compression", po::value(), "set compression level")
; po::variables_map vm;
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm); if (vm.count("help")) {
cout << desc << "\n";
return 1;
} if (vm.count("compression")) {
cout << "Compression level was set to "
<< vm["compression"].as() << ".\n";
} else {
cout << "Compression level was not set.\n";
}
首先用类 options_description 描述所有允许的参数项,类的add_options方法返回定义了operator()的代理对象,调用其operator()用来实际描述参数项,函数参数是参数项名称,相关值信息,参数项描述。本例中,第一个参数项没有值,第二个参数项有一个int类型的值。
其后,定义一个类 variables_map 对象。用来存储参数项的值,其能存储任意类型的值。接着调用store, parse_command_line 和 notify函数,解析命令行参数并保存到vm中。
现在,可以像使用std::map一样来使用variables_map类,但存储的值必须能通过 at 方法找回。假如调用as方法指定的类型和实际类型不符,将抛出异常)
现在自己可以尝试编译一下代码,如何编译的例子如下:
$bin/gcc/debug/first
Compression level was not set.
$bin/gcc/debug/first --help
Allowed options:
--help : produce help message
--compression arg : set compression level $bin/gcc/debug/first --compression 10
Compression level was set to 10.
使用详解
参数项的值,除了int还有其他类型,还有其他属性,我们下面将讨论。完整例子在“example/options_description.cpp”中。
假如我们写一个编译器程序。它有最优化级别, 包含多个路径, 多个输入文件等参数。描述参数项如下:
int opt;
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
("optimization", po::value(&opt)->default_value(10),
"optimization level")
("include-path,I", po::value< vector >(),
"include path")
("input-file", po::value< vector >(), "input file")
;
The "--help" 项和前例一样,在项目中有这个参数项是个好注意。
The "optimization" 项体现两个新特性. 首先,我们传递变量(&opt)地址,这个变量用来保存获得的参数项的值。然后,指定一个缺省值,用在此参数项用户没有设置值的时候。
The "include-path" 项说明了options_description 类接口仅仅来源于命令行的例子。用户喜欢用短参数项名称,“include-path,I”名指出短参数项名是“I”.因此,“--include-path”和“-I”都能用。
The "input-file" 参数项指定处理文件列表。像下面这样写没有问题:
compiler --input-file=a.cpp
但通常情况常常这么写:
compiler a.cpp
这里要解释一下这种用法。
像上例,没有参数名的命令行选项,在这个库里称为“位置参数项”,也能处理。库能解释“a.cpp”等同于“--input-file=a.cpp”。下面是所需的附加的代码:
po::positional_options_description p;
p.add("input-file", -1); po::variables_map vm;
po::store(po::command_line_parser(ac, av).
options(desc).positional(p).run(), vm);
po::notify(vm);
前两行指出所有的“位置参数项”应被翻译成“input-file”项。要注意用 command_line_parser 类解析命令行,而不是 parse_command_line 函数。parse_command_line函数是为处理简单情况对command_line_parser类的封装,但现在要传递附加信息就
不适用了。
现在,所有参数项被描述且被解析。我们暂不实现剩下的编译逻辑,仅仅打印参数项:
if (vm.count("include-path"))
{
cout << "Include paths are: "
<< vm["include-path"].as< vector >() << "\n";
} if (vm.count("input-file"))
{
cout << "Input files are: "
<< vm["input-file"].as< vector >() << "\n";
} cout << "Optimization level is " << opt << "\n";
如何编译的例子如下:
$bin/gcc/debug/options_description --help
Usage: options_description [options]
Allowed options:
--help : produce help message
--optimization arg : optimization level
-I [ --include-path ] arg : include path
--input-file arg : input file
$bin/gcc/debug/options_description
Optimization level is 10
$bin/gcc/debug/options_description --optimization 4 -I foo a.cpp
Include paths are: foo
Input files are: a.cpp
Optimization level is 4
这里有个小问题,“帮助信息”要求指定“--input-file”项名称,这将把用户弄糊涂。在后面的例子中可看到怎样隐藏这个信息。
参数多种来源
要求用户在命令行给我们的编译器指定所有参数不太现实。假如用户安装新库且想传递一个附加命令行参数该怎么做?想实现一次选择多次运行的时候使用该怎么做?可以创建一个配置文件把命令行参数组织在一起来完成这个工作。
当然,解析时需要结合命令行参数和配置文件两方面的值。例如,在命令行指定的“最优化级别”的值将覆盖配置文件的值。另一方面,“包含路径”应该包含命令行和配置文件里两方面的值。
下面看代码。完整代码在“examples/multiple_sources.cpp”。参数项定义有两种细节。首先,定义options_description类的几个实例。原因是,通常情况下,不是所有参数项属性是类似的。一些项,例如上面的“input-file”,应该在自动帮助信息里不出现。一下项仅在配置文件中有意义。其次,帮助信息有组织的输出是个好主意,而不仅仅是参数项的长列表。下面声明几组参数项:
// Declare a group of options that will be
// allowed only on command line
po::options_description generic("Generic options");
generic.add_options()
("version,v", "print version string")
("help", "produce help message")
; // Declare a group of options that will be
// allowed both on command line and in
// config file
po::options_description config("Configuration");
config.add_options()
("optimization", po::value(&opt)->default_value(10),
"optimization level")
("include-path,I",
po::value< vector >()->composing(),
"include path")
; // Hidden options, will be allowed both on command line and
// in config file, but will not be shown to the user.
po::options_description hidden("Hidden options");
hidden.add_options()
("input-file", po::value< vector >(), "input file")
;
注意在"include-path" 项声明中调用composing 方法,说明从不同来源的值应当被合并在一起,下面很快就会看到。
options_description 类的add 方法能被用于进一步组合参数项:
po::options_description cmdline_options;
cmdline_options.add(generic).add(config).add(hidden); po::options_description config_file_options;
config_file_options.add(config).add(hidden); po::options_description visible("Allowed options");
visible.add(generic).add(config);
除了额外需要调用 parse_config_file 和 store 函数以外,参数值的解析和存储和通常一样。 但是当命令行和配置文件中同样的参数被指定了如何处理?通常,首选第一个被存储的值。 这说明了“--optimization”项的值如何产生。对“组合(composing)”项,像“include-file”,值被合并在一起。
如何编译的例子如下:
$bin/gcc/debug/multiple_sources
Include paths are: /opt
Optimization level is 1
$bin/gcc/debug/multiple_sources --help
Allows options: Generic options:
-v [ --version ] : print version string
--help : produce help message Configuration:
--optimization n : optimization level
-I [ --include-path ] path : include path $bin/gcc/debug/multiple_sources --optimization=4 -I foo a.cpp b.cpp
Include paths are: foo /opt
Input files are: a.cpp b.cpp
Optimization level is 4
附录
为加强理解,这里列出了上面提到的完整源代码。
文件example/first.cpp
#include
namespace po = boost::program_options; #include
#include
using namespace std; int main(int ac, char* av[])
{
try { po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
("compression", po::value(), "set compression level")
; po::variables_map vm;
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm); if (vm.count("help")) {
cout << desc << "\n";
return 1;
} if (vm.count("compression")) {
cout << "Compression level was set to "
<< vm["compression"].as() << ".\n";
} else {
cout << "Compression level was not set.\n";
}
}
catch(exception& e) {
cerr << "error: " << e.what() << "\n";
return 1;
}
catch(...) {
cerr << "Exception of unknown type!\n";
} return 0;
}
文件example/options_description.cpp
#include using namespace boost;
namespace po = boost::program_options; #include
#include
#include
using namespace std; // A helper function to simplify the main part.
template
ostream& operator<<(ostream& os, const vector& v)
{
copy(v.begin(), v.end(), ostream_iterator(cout, " "));
return os;
} int main(int ac, char* av[])
{
try {
int opt;
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
("optimization", po::value(&opt)->default_value(10),
"optimization level")
("include-path,I", po::value< vector >(),
"include path")
("input-file", po::value< vector >(), "input file")
; po::positional_options_description p;
p.add("input-file", -1); po::variables_map vm;
po::store(po::command_line_parser(ac, av).
options(desc).positional(p).run(), vm);
po::notify(vm); if (vm.count("help")) {
cout << "Usage: options_description [options]\n";
cout << desc;
return 0;
} if (vm.count("include-path"))
{
cout << "Include paths are: "
<< vm["include-path"].as< vector >() << "\n";
} if (vm.count("input-file"))
{
cout << "Input files are: "
<< vm["input-file"].as< vector >() << "\n";
} cout << "Optimization level is " << opt << "\n";
}
catch(exception& e)
{
cout << e.what() << "\n";
return 1;
}
return 0;
}
文件examples/multiple_sources.cpp
#include
namespace po = boost::program_options; #include
#include
#include
using namespace std; // A helper function to simplify the main part.
template
ostream& operator<<(ostream& os, const vector& v)
{
copy(v.begin(), v.end(), ostream_iterator(cout, " "));
return os;
} int main(int ac, char* av[])
{
try {
int opt; // Declare a group of options that will be
// allowed only on command line
po::options_description generic("Generic options");
generic.add_options()
("version,v", "print version string")
("help", "produce help message")
; // Declare a group of options that will be
// allowed both on command line and in
// config file
po::options_description config("Configuration");
config.add_options()
("optimization", po::value(&opt)->default_value(10),
"optimization level")
("include-path,I",
po::value< vector >()->composing(),
"include path")
; // Hidden options, will be allowed both on command line and
// in config file, but will not be shown to the user.
po::options_description hidden("Hidden options");
hidden.add_options()
("input-file", po::value< vector >(), "input file")
; po::options_description cmdline_options;
cmdline_options.add(generic).add(config).add(hidden); po::options_description config_file_options;
config_file_options.add(config).add(hidden); po::options_description visible("Allowed options");
visible.add(generic).add(config); po::positional_options_description p;
p.add("input-file", -1); po::variables_map vm;
store(po::command_line_parser(ac, av).
options(cmdline_options).positional(p).run(), vm); ifstream ifs("multiple_sources.cfg");
store(parse_config_file(ifs, config_file_options), vm);
notify(vm); if (vm.count("help")) {
cout << visible << "\n";
return 0;
} if (vm.count("version")) {
cout << "Multiple sources example, version 1.0\n";
return 0;
} if (vm.count("include-path"))
{
cout << "Include paths are: "
<< vm["include-path"].as< vector >() << "\n";
} if (vm.count("input-file"))
{
cout << "Input files are: "
<< vm["input-file"].as< vector >() << "\n";
} cout << "Optimization level is " << opt << "\n";
}
catch(exception& e)
{
cout << e.what() << "\n";
return 1;
}
return 0;
}
[C++Boost]程序参数项解析库Program_options使用指南的更多相关文章
- C++的Json解析库:jsoncpp和boost
C++的Json解析库:jsoncpp和boost - hzyong_c的专栏 - 博客频道 - CSDN.NET C++的Json解析库:jsoncpp和boost 分类: 网络编程 开源库 201 ...
- C++的Json解析库:jsoncpp和boost(转)
原文转自 http://blog.csdn.net/hzyong_c/article/details/7163589 JSON(JavaScript Object Notation)跟xml一样也是一 ...
- [转]C++的Json解析库:jsoncpp和boost
JSON(JavaScript Object Notation)跟xml一样也是一种数据交换格式,了解json请参考其官网http://json.org,本文不再对json做介绍,将重点介绍c++的j ...
- Boost.JSON Boost的JSON解析库(1.75首发)
目录 目录 Boost的1.75版本新库 JSON库简介 JSON的简单使用 编码 最通用的方法 使用std::initializer_list json对象的输出 两种对比 解码 简单的解码 增加错 ...
- 【转】编译quickfast解析库(沪深level2行情转码库)
转自http://blog.csdn.net/hacode/article/details/7065889 编译quickfast解析库(沪深level2行情转码库) 目录(?)[-] 1 下载源代 ...
- [terry笔记]Oracle会话追踪(二):TKPROF
接上一笔记[terry笔记]Oracle会话追踪(一):SQL_TRACE&EVENT 10046 http://www.cnblogs.com/kkterry/p/3279282.html ...
- IOS学习:常用第三方库(GDataXMLNode:xml解析库)
IOS学习:常用第三方库(GDataXMLNode:xml解析库) 解析 XML 通常有两种方式,DOM 和 SAX: DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过 ...
- 全解史上最快的JOSN解析库 - alibaba Fastjson
JSON,全称:JavaScript Object Notation,作为一个常见的轻量级的数据交换格式,应该在一个程序员的开发生涯中是常接触的.简洁和清晰的层次结构使得 JSON 成为理想的数据交换 ...
- GDataXMLNode:xml解析库
IOS学习:常用第三方库(GDataXMLNode:xml解析库) 解析 XML 通常有两种方式,DOM 和 SAX: DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过 ...
随机推荐
- 【转载】如何用Maven创建web项目(具体步骤)
使用eclipse插件创建一个web project 首先创建一个Maven的Project如下图 我们勾选上Create a simple project (不使用骨架) 这里的Packing 选择 ...
- 比赛F-F Perpetuum Mobile
比赛F-F Perpetuum Mobile 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=86640#problem/ ...
- 一个简单二叉树的C++实现(一)
很久没有接触二叉树了,写这个当作练手,接下来会比较详细地实现二叉树的各个功能及应用. /* * BinaryTree.cpp * Author: Qiang Xiao * Time: 2015-07- ...
- BZOJ 1261: [SCOI2006]zh_tree( 区间dp )
dp(l, r)表示[l, r]这段作为一棵树的最小访问代价. 对于dp(l, r), 我们枚举它的根x, 则dp(l, r) = min(dp(l, x-1)+dp(x+1, r)+C*fx) + ...
- BZOJ 1880: [Sdoi2009]Elaxia的路线( 最短路 + dp )
找出同时在他们最短路上的边(dijkstra + dfs), 组成新图, 新图DAG的最长路就是答案...因为两人走同一条路但是不同方向也可以, 所以要把一种一个的s,t换一下再更新一次答案 ---- ...
- [C#参考]委托机制
1. 委托概述 这是一个新的概念,但是其本质并不是什么新鲜的事物,委托本质上就是一个类.只不过一般的类是数据的集合,委托保存的是一个或者多个方法.委托是引用类型,因此委托有引用和对象,同时委托对象中包 ...
- python命令行解析工具argparse模块【2】
上一节,我们简要的介绍了argparse的用法,接下来几节,将详细讲解其中的参数及用法,这一节我们讲解ArgumentParser对象. argparse.ArgumentParser([descri ...
- js中去除换行(\r\n)
解决方法:replace(/\r\n/g,"").replace("\n","") 测试: <script> var str = ...
- 解决phpmyadmin配置文件的权限问题
如果部署的phpmyadmin权限为所有人可写,即权限为777,就会报”Wrong permissions on configuration file, should not be world wri ...
- Python web框架有哪些
简单易学的web.py, 大型的django:文档最完善.市场占有率最高.招聘职位最多. Tornado 具体看:http://feilong.me/2011/01/talk-about-python ...