[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;
}
时间: 2024-09-30 18:42:21

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

[Redhat9.0]Models-3安装备忘录之LINUX篇

[Redhat9.0]Models-3安装备忘录之MODELS-3篇(未完待续……) 2010-01-26 11:32:54|  分类: Models-3|举报|字号 订阅 写在前面:不知道是因为版本还是机器的问题,总之smoke现在进入瓶颈阶段了,僵持了N久之后导师终于坚持不下去了,现在models-3只好暂时停止,真是可惜啊.现在主攻MM5,期望不要再出什么状况,时间不是我能耗的起的啊! ----------------------------------------------------

pugixml库之xml解析库

前言: 本文介绍c++编写的xml解析库--pugixml,能解析xml内容,支持xpath解析,同时能够跨linux平台,非常方便. 总结一下使用步骤和简单的使用方法: 使用pugixml库需要三个文件:pugiconfig.h/pugixml.h/pugixml.cpp,可直接从gugixml官网下载,将其加入工程,使用处包含头文件pugiconfig.h/pugixml.h即可. 加载xml文件,使用xml_document类的load_file接口: std::strFile = "..

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

IOS学习:常用第三方库(GDataXMLNode:xml解析库) 分类: ios开发学习2013-05-30 09:45 4443人阅读 评论(0) 收藏 举报 iOSXMLGDataXMLNode 一.GDataXMLNode说明 GDataXMLNode是Google提供的用于XML数据处理的类集.该类集对libxml2--DOM处理方式进行了封装,能对较小或中等的xml文档进行读写操作且支持XPath语法. 使用方法: 1.获取GDataXMLNode.h/m文件,将GDataXMLNo

Boost,Eigen,Flann—C++标准库预备役

Boost,Eigen,Flann—C++标准库预备役 第一预备役:Boost Boost库是为C++语言标准库提供扩展的一些C++程序库的总称. Boost库由Boost社区组织开发.维护.其目的是为C++程序员提供免费.同行审查的.可移植的程序库.Boost库可以与C++标准库完美共同工作,并且为其提供扩展功能.Boost库使用Boost License来授权使用,根据该协议,商业的非商业的使用都是允许并鼓励的. Boost社区建立的初衷之一就是为C++的标准化工作提供可供参考的实现,Boo

inifile 一个轻量级的INI文件解析库

ini文件是一种常见的配置文件.它以简单的文字与简单的结构组成.INI文件会以不同的扩展名,如".ini.",".cfg",".conf"等. INI文件的格式 INI文件由3个重要的部分组成:参数(parameters),段(sections)和注释(comments).其格式如下: 段(sections) [section] 参数(parameters) name=value 注释(comments) ;comments 每个段包括段名,注释

uniVocity-parsers:一款强大的CSV/TSV/定宽文本文件解析库(Java)

uniVocity-parsers 是一个开源的Java项目. 针对CSV/TSV/定宽文本文件的解析,它以简洁的API开发接口提供了丰富而强大的功能.后面会做进一步介绍. 和其他解析库有所不同,uniVocity-parsers以高性能.可扩展为出发点,设计了一套自有架构.基于这套架构,开发者可以构建出新的文件解析器. 1. 概述 作为一名Java开发者,我目前正在参与开发一个Web项目,该项目帮助通信运营商评估当前的网络,并给出解决方案. 在该项目中,CSV文件扮演着至关重要的角色,它是运营

一个C++写的html解析库的简介

学习Qt也有段时间了,前一阵子想着写一个Qt版的博客园桌面端.现阶段主要想实现: (1)显示博客园主页的推荐的那个些文章的条目(包括作者的图像.该博客的浏览次数.发布时间等). (2)可以登陆自己的博客园账号,并显示自己的博客文章. (3)点击显示的博客文章条目时可以弹出窗口显示该片博客的内容. 同时还要实现自动刷新功能. 但是在编写的过程中,需要跟reply回来的html文档打交道,需要一个可以解析html文档的库.我在网上搜索了找到了C++编写的html解析库有htmlcxx.和google

cmdline —— 轻量级的C++命令行解析库

平时用C++写一些命令行工具,需要解析命令行的输入参数,这是一项繁琐并且容易出错的工作,我们不应该将主要精力放在这上面,可以考虑使用开源的库,下面的cmdline就是其中非常好用的一款. cmdline介绍 cmdline 是一个非常简单好用的C++命令行解析库,其基于模板,所以使用很简单,写出的代码也很优雅.由于其只包含一个头文件,所以很容易集成到自己的项目中. cmdline项目托管地址Github:https://github.com/tanakh/cmdline cmdline使用 下面

ELF格式解析库之抽象数据类型

抽象?抽谁的象? ELF是一种链接执行格式,它规定了对于一个ELF文件的基本数据类型是什么样的.可是,要解析一个ELF文件,而这个ELF文件或者是32Bits 或者是 64Bits,反正字长是未定的,怎么办?难道我们要定义两套解析的接口,以对应不同的字长的ELF文件吗?如果要这样做,不是不可以,只是那样做为接口的设计增加了太大的负担.这里我们采用"抽象"的方式,将已有的两套基础数据结构封装成一个兼容的数据结构.这样,我们设计解析接口时,可以做到尽量的简化,大大的减轻了工作量. 因此,这