介绍

程序参数项(program options)是一系列name=value对,program_options 允许程序开发者获得通过命令行(command line)和配置文件(config file)获取这些参数项。

为什么需要这样一个库?为什么比你手工写代码分解命令行参数要好?

  • 使用更容易。定义参数处理的语法简单,库自身很小。像转换参数值到指定的类型和保存参数值到变量的事情都是自动处理。
  • 错误报告更友好。可报告错误的命令行参数。另外这个库能自动生成使用帮助,避免手工更新使用帮助导致的不一致。
  • 参数能从不同地方读取。当命令行参数不能满足要求,需要改用配置文件或环境变量。
    这些功能都能支持,代码改动很小。

使用指南

在本节,我们从最简单的例子开始,学习program_options库的通常用法。下面的例子仅仅是代码片断,完整例子在“BOOST_ROOT/libs/program_options/example”目录里。对所有例子,假定都在如下名字空间中:

  1. namespace po = boost::program_options;

快速入门

第一个例子尽可能简单:仅仅包含两个参数项。代码如下(完整代码见“example/first.cpp”):

  1. // Declare the supported options.
  2. po::options_description desc("Allowed options");
  3. desc.add_options()
  4. ("help", "produce help message")
  5. ("compression", po::value(), "set compression level")
  6. ;
  7.  
  8. po::variables_map vm;
  9. po::store(po::parse_command_line(ac, av, desc), vm);
  10. po::notify(vm);
  11.  
  12. if (vm.count("help")) {
  13. cout << desc << "\n";
  14. return 1;
  15. }
  16.  
  17. if (vm.count("compression")) {
  18. cout << "Compression level was set to "
  19. << vm["compression"].as() << ".\n";
  20. } else {
  21. cout << "Compression level was not set.\n";
  22. }

首先用类 options_description 描述所有允许的参数项,类的add_options方法返回定义了operator()的代理对象,调用其operator()用来实际描述参数项,函数参数是参数项名称,相关值信息,参数项描述。本例中,第一个参数项没有值,第二个参数项有一个int类型的值。

其后,定义一个类 variables_map 对象。用来存储参数项的值,其能存储任意类型的值。接着调用store, parse_command_line 和 notify函数,解析命令行参数并保存到vm中。

现在,可以像使用std::map一样来使用variables_map类,但存储的值必须能通过 at 方法找回。假如调用as方法指定的类型和实际类型不符,将抛出异常)

现在自己可以尝试编译一下代码,如何编译的例子如下:

  1. $bin/gcc/debug/first
  2. Compression level was not set.
  3. $bin/gcc/debug/first --help
  4. Allowed options:
  5. --help : produce help message
  6. --compression arg : set compression level
  7.  
  8. $bin/gcc/debug/first --compression 10
  9. Compression level was set to 10.

使用详解

参数项的值,除了int还有其他类型,还有其他属性,我们下面将讨论。完整例子在“example/options_description.cpp”中。

假如我们写一个编译器程序。它有最优化级别, 包含多个路径, 多个输入文件等参数。描述参数项如下:
 

  1. int opt;
  2. po::options_description desc("Allowed options");
  3. desc.add_options()
  4. ("help", "produce help message")
  5. ("optimization", po::value(&opt)->default_value(10),
  6. "optimization level")
  7. ("include-path,I", po::value< vector >(),
  8. "include path")
  9. ("input-file", po::value< vector >(), "input file")
  10. ;

The "--help" 项和前例一样,在项目中有这个参数项是个好注意。

The "optimization" 项体现两个新特性. 首先,我们传递变量(&opt)地址,这个变量用来保存获得的参数项的值。然后,指定一个缺省值,用在此参数项用户没有设置值的时候。
 

The "include-path" 项说明了options_description 类接口仅仅来源于命令行的例子。用户喜欢用短参数项名称,“include-path,I”名指出短参数项名是“I”.因此,“--include-path”和“-I”都能用。
 

The "input-file" 参数项指定处理文件列表。像下面这样写没有问题:

  1. compiler --input-file=a.cpp

但通常情况常常这么写:

  1. compiler a.cpp

这里要解释一下这种用法。

像上例,没有参数名的命令行选项,在这个库里称为“位置参数项”,也能处理。库能解释“a.cpp”等同于“--input-file=a.cpp”。下面是所需的附加的代码:

  1. po::positional_options_description p;
  2. p.add("input-file", -1);
  3.  
  4. po::variables_map vm;
  5. po::store(po::command_line_parser(ac, av).
  6. options(desc).positional(p).run(), vm);
  7. po::notify(vm);

前两行指出所有的“位置参数项”应被翻译成“input-file”项。要注意用 command_line_parser 类解析命令行,而不是 parse_command_line 函数。parse_command_line函数是为处理简单情况对command_line_parser类的封装,但现在要传递附加信息就
不适用了。

现在,所有参数项被描述且被解析。我们暂不实现剩下的编译逻辑,仅仅打印参数项:

  1. if (vm.count("include-path"))
  2. {
  3. cout << "Include paths are: "
  4. << vm["include-path"].as< vector >() << "\n";
  5. }
  6.  
  7. if (vm.count("input-file"))
  8. {
  9. cout << "Input files are: "
  10. << vm["input-file"].as< vector >() << "\n";
  11. }
  12.  
  13. cout << "Optimization level is " << opt << "\n";

如何编译的例子如下:

  1. $bin/gcc/debug/options_description --help
  2. Usage: options_description [options]
  3. Allowed options:
  4. --help : produce help message
  5. --optimization arg : optimization level
  6. -I [ --include-path ] arg : include path
  7. --input-file arg : input file
  8. $bin/gcc/debug/options_description
  9. Optimization level is 10
  10. $bin/gcc/debug/options_description --optimization 4 -I foo a.cpp
  11. Include paths are: foo
  12. Input files are: a.cpp
  13. Optimization level is 4

这里有个小问题,“帮助信息”要求指定“--input-file”项名称,这将把用户弄糊涂。在后面的例子中可看到怎样隐藏这个信息。

参数多种来源

 

要求用户在命令行给我们的编译器指定所有参数不太现实。假如用户安装新库且想传递一个附加命令行参数该怎么做?想实现一次选择多次运行的时候使用该怎么做?可以创建一个配置文件把命令行参数组织在一起来完成这个工作。

当然,解析时需要结合命令行参数和配置文件两方面的值。例如,在命令行指定的“最优化级别”的值将覆盖配置文件的值。另一方面,“包含路径”应该包含命令行和配置文件里两方面的值。

下面看代码。完整代码在“examples/multiple_sources.cpp”。参数项定义有两种细节。首先,定义options_description类的几个实例。原因是,通常情况下,不是所有参数项属性是类似的。一些项,例如上面的“input-file”,应该在自动帮助信息里不出现。一下项仅在配置文件中有意义。其次,帮助信息有组织的输出是个好主意,而不仅仅是参数项的长列表。下面声明几组参数项:

  1. // Declare a group of options that will be
  2. // allowed only on command line
  3. po::options_description generic("Generic options");
  4. generic.add_options()
  5. ("version,v", "print version string")
  6. ("help", "produce help message")
  7. ;
  8.  
  9. // Declare a group of options that will be
  10. // allowed both on command line and in
  11. // config file
  12. po::options_description config("Configuration");
  13. config.add_options()
  14. ("optimization", po::value(&opt)->default_value(10),
  15. "optimization level")
  16. ("include-path,I",
  17. po::value< vector >()->composing(),
  18. "include path")
  19. ;
  20.  
  21. // Hidden options, will be allowed both on command line and
  22. // in config file, but will not be shown to the user.
  23. po::options_description hidden("Hidden options");
  24. hidden.add_options()
  25. ("input-file", po::value< vector >(), "input file")
  26. ;

注意在"include-path" 项声明中调用composing 方法,说明从不同来源的值应当被合并在一起,下面很快就会看到。

options_description 类的add 方法能被用于进一步组合参数项:

  1. po::options_description cmdline_options;
  2. cmdline_options.add(generic).add(config).add(hidden);
  3.  
  4. po::options_description config_file_options;
  5. config_file_options.add(config).add(hidden);
  6.  
  7. po::options_description visible("Allowed options");
  8. visible.add(generic).add(config);

除了额外需要调用 parse_config_file 和 store 函数以外,参数值的解析和存储和通常一样。 但是当命令行和配置文件中同样的参数被指定了如何处理?通常,首选第一个被存储的值。 这说明了“--optimization”项的值如何产生。对“组合(composing)”项,像“include-file”,值被合并在一起。

如何编译的例子如下:

  1. $bin/gcc/debug/multiple_sources
  2. Include paths are: /opt
  3. Optimization level is 1
  4. $bin/gcc/debug/multiple_sources --help
  5. Allows options:
  6.  
  7. Generic options:
  8. -v [ --version ] : print version string
  9. --help : produce help message
  10.  
  11. Configuration:
  12. --optimization n : optimization level
  13. -I [ --include-path ] path : include path
  14.  
  15. $bin/gcc/debug/multiple_sources --optimization=4 -I foo a.cpp b.cpp
  16. Include paths are: foo /opt
  17. Input files are: a.cpp b.cpp
  18. Optimization level is 4

附录

为加强理解,这里列出了上面提到的完整源代码。

文件example/first.cpp

 

  1. #include
  2. namespace po = boost::program_options;
  3.  
  4. #include
  5. #include
  6. using namespace std;
  7.  
  8. int main(int ac, char* av[])
  9. {
  10. try {
  11.  
  12. po::options_description desc("Allowed options");
  13. desc.add_options()
  14. ("help", "produce help message")
  15. ("compression", po::value(), "set compression level")
  16. ;
  17.  
  18. po::variables_map vm;
  19. po::store(po::parse_command_line(ac, av, desc), vm);
  20. po::notify(vm);
  21.  
  22. if (vm.count("help")) {
  23. cout << desc << "\n";
  24. return 1;
  25. }
  26.  
  27. if (vm.count("compression")) {
  28. cout << "Compression level was set to "
  29. << vm["compression"].as() << ".\n";
  30. } else {
  31. cout << "Compression level was not set.\n";
  32. }
  33. }
  34. catch(exception& e) {
  35. cerr << "error: " << e.what() << "\n";
  36. return 1;
  37. }
  38. catch(...) {
  39. cerr << "Exception of unknown type!\n";
  40. }
  41.  
  42. return 0;
  43. }

文件example/options_description.cpp

  1. #include
  2.  
  3. using namespace boost;
  4. namespace po = boost::program_options;
  5.  
  6. #include
  7. #include
  8. #include
  9. using namespace std;
  10.  
  11. // A helper function to simplify the main part.
  12. template
  13. ostream& operator<<(ostream& os, const vector& v)
  14. {
  15. copy(v.begin(), v.end(), ostream_iterator(cout, " "));
  16. return os;
  17. }
  18.  
  19. int main(int ac, char* av[])
  20. {
  21. try {
  22. int opt;
  23. po::options_description desc("Allowed options");
  24. desc.add_options()
  25. ("help", "produce help message")
  26. ("optimization", po::value(&opt)->default_value(10),
  27. "optimization level")
  28. ("include-path,I", po::value< vector >(),
  29. "include path")
  30. ("input-file", po::value< vector >(), "input file")
  31. ;
  32.  
  33. po::positional_options_description p;
  34. p.add("input-file", -1);
  35.  
  36. po::variables_map vm;
  37. po::store(po::command_line_parser(ac, av).
  38. options(desc).positional(p).run(), vm);
  39. po::notify(vm);
  40.  
  41. if (vm.count("help")) {
  42. cout << "Usage: options_description [options]\n";
  43. cout << desc;
  44. return 0;
  45. }
  46.  
  47. if (vm.count("include-path"))
  48. {
  49. cout << "Include paths are: "
  50. << vm["include-path"].as< vector >() << "\n";
  51. }
  52.  
  53. if (vm.count("input-file"))
  54. {
  55. cout << "Input files are: "
  56. << vm["input-file"].as< vector >() << "\n";
  57. }
  58.  
  59. cout << "Optimization level is " << opt << "\n";
  60. }
  61. catch(exception& e)
  62. {
  63. cout << e.what() << "\n";
  64. return 1;
  65. }
  66. return 0;
  67. }

 

文件examples/multiple_sources.cpp

  1. #include
  2. namespace po = boost::program_options;
  3.  
  4. #include
  5. #include
  6. #include
  7. using namespace std;
  8.  
  9. // A helper function to simplify the main part.
  10. template
  11. ostream& operator<<(ostream& os, const vector& v)
  12. {
  13. copy(v.begin(), v.end(), ostream_iterator(cout, " "));
  14. return os;
  15. }
  16.  
  17. int main(int ac, char* av[])
  18. {
  19. try {
  20. int opt;
  21.  
  22. // Declare a group of options that will be
  23. // allowed only on command line
  24. po::options_description generic("Generic options");
  25. generic.add_options()
  26. ("version,v", "print version string")
  27. ("help", "produce help message")
  28. ;
  29.  
  30. // Declare a group of options that will be
  31. // allowed both on command line and in
  32. // config file
  33. po::options_description config("Configuration");
  34. config.add_options()
  35. ("optimization", po::value(&opt)->default_value(10),
  36. "optimization level")
  37. ("include-path,I",
  38. po::value< vector >()->composing(),
  39. "include path")
  40. ;
  41.  
  42. // Hidden options, will be allowed both on command line and
  43. // in config file, but will not be shown to the user.
  44. po::options_description hidden("Hidden options");
  45. hidden.add_options()
  46. ("input-file", po::value< vector >(), "input file")
  47. ;
  48.  
  49. po::options_description cmdline_options;
  50. cmdline_options.add(generic).add(config).add(hidden);
  51.  
  52. po::options_description config_file_options;
  53. config_file_options.add(config).add(hidden);
  54.  
  55. po::options_description visible("Allowed options");
  56. visible.add(generic).add(config);
  57.  
  58. po::positional_options_description p;
  59. p.add("input-file", -1);
  60.  
  61. po::variables_map vm;
  62. store(po::command_line_parser(ac, av).
  63. options(cmdline_options).positional(p).run(), vm);
  64.  
  65. ifstream ifs("multiple_sources.cfg");
  66. store(parse_config_file(ifs, config_file_options), vm);
  67. notify(vm);
  68.  
  69. if (vm.count("help")) {
  70. cout << visible << "\n";
  71. return 0;
  72. }
  73.  
  74. if (vm.count("version")) {
  75. cout << "Multiple sources example, version 1.0\n";
  76. return 0;
  77. }
  78.  
  79. if (vm.count("include-path"))
  80. {
  81. cout << "Include paths are: "
  82. << vm["include-path"].as< vector >() << "\n";
  83. }
  84.  
  85. if (vm.count("input-file"))
  86. {
  87. cout << "Input files are: "
  88. << vm["input-file"].as< vector >() << "\n";
  89. }
  90.  
  91. cout << "Optimization level is " << opt << "\n";
  92. }
  93. catch(exception& e)
  94. {
  95. cout << e.what() << "\n";
  96. return 1;
  97. }
  98. return 0;
  99. }

[C++Boost]程序参数项解析库Program_options使用指南的更多相关文章

  1. C++的Json解析库:jsoncpp和boost

    C++的Json解析库:jsoncpp和boost - hzyong_c的专栏 - 博客频道 - CSDN.NET C++的Json解析库:jsoncpp和boost 分类: 网络编程 开源库 201 ...

  2. C++的Json解析库:jsoncpp和boost(转)

    原文转自 http://blog.csdn.net/hzyong_c/article/details/7163589 JSON(JavaScript Object Notation)跟xml一样也是一 ...

  3. [转]C++的Json解析库:jsoncpp和boost

    JSON(JavaScript Object Notation)跟xml一样也是一种数据交换格式,了解json请参考其官网http://json.org,本文不再对json做介绍,将重点介绍c++的j ...

  4. Boost.JSON Boost的JSON解析库(1.75首发)

    目录 目录 Boost的1.75版本新库 JSON库简介 JSON的简单使用 编码 最通用的方法 使用std::initializer_list json对象的输出 两种对比 解码 简单的解码 增加错 ...

  5. 【转】编译quickfast解析库(沪深level2行情转码库)

     转自http://blog.csdn.net/hacode/article/details/7065889 编译quickfast解析库(沪深level2行情转码库) 目录(?)[-] 1 下载源代 ...

  6. [terry笔记]Oracle会话追踪(二):TKPROF

    接上一笔记[terry笔记]Oracle会话追踪(一):SQL_TRACE&EVENT 10046 http://www.cnblogs.com/kkterry/p/3279282.html ...

  7. IOS学习:常用第三方库(GDataXMLNode:xml解析库)

    IOS学习:常用第三方库(GDataXMLNode:xml解析库) 解析 XML 通常有两种方式,DOM 和 SAX: DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过 ...

  8. 全解史上最快的JOSN解析库 - alibaba Fastjson

    JSON,全称:JavaScript Object Notation,作为一个常见的轻量级的数据交换格式,应该在一个程序员的开发生涯中是常接触的.简洁和清晰的层次结构使得 JSON 成为理想的数据交换 ...

  9. GDataXMLNode:xml解析库

    IOS学习:常用第三方库(GDataXMLNode:xml解析库) 解析 XML 通常有两种方式,DOM 和 SAX: DOM解析XML时,读入整个XML文档并构建一个驻留内存的树结构(节点树),通过 ...

随机推荐

  1. android 基础学习图片六progross

    加载进度条应用

  2. Android之判断设备网络连接状态,并判断连接方式

    在Android开发过程中,对于一个需要连接网络的Android设备,对设备的网络状态检测是很有必要的!有很多的App都需要连接网络.判断设备是否已经连接网络,并且在连接网络的状态下判断是wifi无线 ...

  3. 解决servlet乱码问题

    1) request中的中文乱码 a) POST方式提交 在获得提交表单信息之前调用request.setCharactersEncoding("UTF-8"); b) GET方式 ...

  4. r语言之散点图绘制及参数

    一个简单的例子: > plot(cars$dist~cars$speed,+ main="车位移与速度的关系",+ xlab="速度",+ ylab=&q ...

  5. openstack 入门1

    介绍 Rackspace & NASA软件开源项目的组合安装配置复杂基础设施资源的系统管理平台 (网络,计算,存储)个人打井 vs 自来水厂 组件&原理 Horizon -- UI模块 ...

  6. Django : Table 'MyDjango.django_admin_log' doesn't exist

    原因: 添加admin之后,没有运行 manage.py syncdb 解决方法: 在命令行中运行manage.py syncdb 即可 运行截图:

  7. linux 进程通信

    IPC: 管道,FIFO,信号,消息队列(system v/ posix),共享内存(system v/  posix),socket 同步机制: 互斥锁,条件变量,记录上锁, 信号量(system ...

  8. C#调用Java方法

    C#调用Java方法(详细实例) 阅读目录 C#调用c++ C#调用JAVA方法 C#可以直接引用C++的DLL和转换JAVA写好的程序.最近由于工作原因接触这方面比较多,根据实际需求,我们通过一个具 ...

  9. 第三节 ISBN 码 / ISSN 码

    ISBN与ISSNEAN的用途很广,除了我国的商品条码CAN以及日本商品条码JAN外,目前国际认可的书籍代号与期刊号的条码,也都是由EAN变身而来的.书籍的国际认可代号称为国际标准书号(Interna ...

  10. QT图片旋转

    目前发现有两种方法,如下: 1.使用QPixmap的transformed函数旋转,这个函数默认是以图片中心为旋转点,不能随意设置旋转点,使用如下: QMatrix leftmatrix; leftm ...