1、阅读rviz中的源码时在rviz/visualizer_app.cpp中遇到如下代码:

  

po::options_description options;
    options.add_options()
      ("help,h", "Produce this help message")
      ("splash-screen,s", po::value<std::string>(), "A custom splash-screen image to display")
      ("help-file", po::value<std::string>(), "A custom html file to show as the help screen")
      ("display-config,d", po::value<std::string>(), "A display config file (.rviz) to load")
      ("fixed-frame,f", po::value<std::string>(), "Set the fixed frame")
      ("ogre-log,l", "Enable the Ogre.log file (output in cwd) and console output.")
      ("in-mc-wrapper", "Signal that this is running inside a master-chooser wrapper")
      ("opengl", po::value<int>(), "Force OpenGL version (use '--opengl 210' for OpenGL 2.1 compatibility mode)")
      ("disable-anti-aliasing", "Prevent rviz from trying to use anti-aliasing when rendering.")
      ("no-stereo", "Disable the use of stereo rendering.")
      ("verbose,v", "Enable debug visualizations")
      ("log-level-debug", "Sets the ROS logger level to debug.");

  其中po是命名空间:namespace po = boost::program_options;

  看到options对象的成员函数add_options()后面接了一连串的括号,表示很不理解,在网上查了下相关资料,整理下自己的学习所得,顺便在这里记录下来。

  实际上上面使用了boost库中的program_options,即程序参数项,它是由一系列的(name,value)键值对构成,program_options允许程序开发者获得通过命令行和配置文件获取这些参数项。

  使用program_options的好处:  

    1、使用更容易。定义参数处理的语法简单,库自身很小,比如转换参数值到指定的类型和保存参数值到变量的事情都是自动处理。

    2、错误报告更友好。可报告错误的命令行参数,库能自动生成使用帮助,避免手工更新使用帮助导致的不一致。

    3、参数能从不同的地方读取,当命令行参数不能满足要求,需要改用配置文件或环境变量,这些功能都能支持,代码改动很小。

  program_options的使用主要通过下面三个组件完成:
          组件名                   作用
    options_description(选项描述器)             描述当前的程序定义了哪些选项
    parse_command_line(选项分析器)         解析由命令行输入的参数
    variables_map(选项存储器)               容器,用于存储解析后的选项

  使用时添加头文件

  #include <boost/program_options.hpp>

  可以把命名空间简化:
  namespace po = boost::program_options;

  

program_options代码流程

  

  program_options对象的成员函数add_options()后面可以加无限多的()是因为此函数返回值类型是options_description_easy_init,函数申明如下:

options_description_easy_init add_options();
  options_description_easy_init的类型为: 
/** Class which provides convenient creation syntax to option_description.
     */
    class BOOST_PROGRAM_OPTIONS_DECL options_description_easy_init {
    public:
        options_description_easy_init(options_description* owner);

        options_description_easy_init&
        operator()(const char* name,
                   const char* description);

        options_description_easy_init&
        operator()(const char* name,
                   const value_semantic* s);

        options_description_easy_init&
        operator()(const char* name,
                   const value_semantic* s,
                   const char* description);

    private:
        options_description* owner;
    };

  显然,类重载了()符号,

 
  

  以下内容来源于以下两个博客

  https://blog.csdn.net/cchd0001/article/details/43967451

  https://blog.csdn.net/morning_color/article/details/50241987

  显然options_description是Boost.Program_options库的一个类,Program_options可以用来解析命令行参数、环境变量或者配置文件。program options是一系列pair<name,value>组成的选项列表,它允许程序通过命令行或配置文件来读取这些参数选项。

定义并添加命令说明

int opt;
/* 类 options_description 是存储选项详细信息的类 */
options_description parser("name_your_like");
/*add_option() 支持() 操作. 多次调用add_options() 的效果等同于将所有的选项使用() 并列声明*/
parser.add_options()
         /*无参数的选项格式 : "命令名" , "命令说明" */
         ("help", "produce help message")
         /* 有参赛的选项格式 :
          "命令名" , "参数说明" , "命令说明" */
         ("set-float" ,value<float>(), "set a float parameter")
         /* 参数对应已有数据(特定地址) , 并且有初始值 : */
         (),
             "optimization level")
         /* 支持短选项 ( --include-path 和 -I 等效 ) ,
            多次调用存在依次vector中 */
         ("include-path,I", value< vector<string> >(),
             "include path")
        ;

解析命令行 , 存储在variables_map 类的变量中

/* variables_map 类是用来存储具体传入参数数据的类 , 和map很相似. 使用as接口来传出数据 */
variables_map vm;
/* ac 就是参数个数 , av 就是参数列表指针 */
/* int ac , const char ** av */
/* parse_command_line 接口不支持猜测选项 */
store(parse_command_line(ac, av, desc), vm);
notify(vm);    

注意: 如果传入没有定义的选项, 会抛出异常!

判断命令是否触发 , 以 help 为例

/* variables_map 使用 count 接口来判断具体选项是否触发 */
if (vm.count("help")) {
   /*如果触发就输出命令说明 , option_description 类重载了 << 行为, 将格式化的输出
   命令说明 */
    cout << desc << "\n";
    ;
}

取出传入的参数 , 以上面的float参数为例

首先, 如果已经指定了一个接受数据 [ 比如 : ("optimization", value<int>(&opt)->default_value(10), "optimization level") ]的话,就可以直接使用它.

if (vm.count("set-float")) {
    cout << "set-float "<<
    /*map直接使用键值当index , 然后使用as< 具体类型> 接口来取出参数*/
    vm["set-float"].as<float>() << ".\n";
} else {
    cout << "float not set\n";
}

定义默认参数.

上面的例子中 ,如下操作:

    $ a.out –set-float=0.131415926
    $ set-float 0.131415926

然而假设我们想要以下面的命令实现上面的效果:

    $ a.out 0.131415926
    $ set-float 0.131415926 

就需要设置set-float 为默认的参数.

int opt;
options_description parser("name_your_like");
parser.add_options()
         ("help", "produce help message")
         ("set-float" ,value<float>(), "set a float parameter")
         (),
             "optimization level")
         ("include-path,I", value< vector<string> >(),
             "include path")
        ;
/* 定义一个可以猜测的命令 positional_options_description */
positional_options_description p;
/* 指定猜测的时候参数的位置, -1 标识没有任何限制 */
p.add();

variables_map vm;
/* 使用可以猜测的命令行解析接口来解析 */
store(command_line_parser(ac, av).options(desc).positional(p).run(), vm);
notify(vm);  

这样就支持了默认选项是 –set-float

对配置文件的支持

 /*将文件读入流*/
 ifstream ifs("file_name");
 /* 调用解析文件接口 */
 store(parse_config_file(ifs, desc), vm);
 notify(vm); 

下面的代码是boost::program_options的一个简单的用法示例.
该示例中指定了两个选项,分别是–help和–filename.

//linux系统下,编译选项需加上 -lboost_program_options

#include <iostream>
#include <string>
#include <boost/program_options.hpp>
namespace  bpo = boost::program_options;

int main(int argc, char const *argv[])
{
    //步骤一: 构造选项描述器和选项存储器
    //选项描述器,其参数为该描述器的名字
    bpo::options_description opts("all options");
    //选项存储器,继承自map容器
    bpo::variables_map vm;

    //步骤二: 为选项描述器增加选项
    //其参数依次为: key, value的类型,该选项的描述
    opts.add_options()
    ("filename", bpo::value<std::string>(), "the file name which want to be found")
    ("help", "this is a program to find a specified file");

    //步骤三: 先对命令行输入的参数做解析,而后将其存入选项存储器
    //如果输入了未定义的选项,程序会抛出异常,所以对解析代码要用try-catch块包围
    try{
        //parse_command_line()对输入的选项做解析
        //store()将解析后的结果存入选项存储器
        bpo::store(bpo::parse_command_line(argc, argv, opts), vm);
    }
    catch(...){
        std::cout << "输入的参数中存在未定义的选项!\n";
        ;
    }

    //步骤四: 参数解析完毕,处理实际信息
    //count()检测该选项是否被输入
    if(vm.count("help") ){//若参数中有help选项
        //options_description对象支持流输出, 会自动打印所有的选项信息
        std::cout << opts << std::endl;
    }
    if(vm.count("filename") ){
        //variables_map(选项存储器)是std::map的派生类,可以像关联容器一样使用,
        //通过operator[]来取出其中的元素.但其内部的元素类型value_type是boost::any,
        //用来存储不确定类型的参数值,必须通过模板成员函数as<type>()做类型转换后,
        //才能获取其具体值.
        std::cout << "find " << vm["filename"].as<std::string>() << std::endl;
    }
    if(vm.empty() ){
        std::cout << "no options found \n";
    }
    ;
}

在编译后(假设在linux系统下其编译后的可执行文件为a.out)
输入

./a.out --help

则其输出为:

all options:
    –filename arg the file name which want to be found
    –help this is a program to find a specified file

输入

./a.out --filename=program_test

则其输出为

find program_test

若不指定选项,即输入

./a.out

则输出为

no options found

示例二

下面的这个示例主要用来说明外部变量,参数默认值以及一个选项对应多个值的情况
这段代码主要有四个选项:

/*
–apple : 苹果的数量
–orange:橘子的数量
–address:水果的生产地,可指定多个生产地
–help: 打印帮助信息
*/

///////////////////////////////////////////
//计算橘子和苹果的总数量,可以指定多个生产地    //
//编译选项加上 -lboost_program_options     //
///////////////////////////////////////////
#include <iostream>
#include <vector>
#include <string>
#include <boost/program_options.hpp>
namespace bpo = boost::program_options;  

int main(int argc, char const *argv[])
{
    //外部变量,用于保存获取的参数值
    , orange_num = ;
    std::vector<std::string> addr;
    bpo::options_description opt("all options");  

    opt.add_options()
    //指定该参数的默认值
    // "apple,a" : 指定选项的全写形式为 --apple, 简写形式为 -a
    //value<type>(ptr) : ptr为该选项对应的外部变量的地址, 当该选项被解析后,
    //可通过下面的notify()函数将选项的值赋给该外部变量,该变量的值会自动更新
    //defaut_value(num) : num为该选项的默认值, 若命令行中未输入该选项, 则该选项的值取为num
    (), "苹果的数量")
    (), "橘子的数量")
    //该参数的实际类型为vector,所以命令行中输入的值可以是多个,
    //multitoken()的作用就是告诉编译器,该选项可接受多个值
    ("address", bpo::value<std::vector<std::string> >()->multitoken(), "生产地")
    ("help", "计算苹果和橘子的总数量");  

    bpo::variables_map vm;  

    try{
        bpo::store(parse_command_line(argc, argv, opt), vm);
    }
    catch(...){
        std::cout << "输入的参数中存在未定义的选项!\n";
        ;
    }
    //参数解析完成后,通知variables_map去更新所有的外部变量
    //这句话执行后, 会使得apple_num和orange_num的值自动更新为选项指定的值
    bpo::notify(vm);  

    if(vm.count("help") ){
        std::cout << opt << std::endl;
        ;
    }
    if(vm.count("address") ){
        std::cout << "生产地为:";
        //遍历选项值
        for(auto& str : vm["address"].as<std::vector<std::string> >() )
            std::cout << str << " ";
        std::cout << std::endl;
    }
    std::cout << "苹果的数量:" << apple_num << std::endl;
    std::cout << "橘子的数量:" << orange_num << std::endl;
    std::cout << "总数量数量:" << orange_num + apple_num << std::endl;
    ;
}  

输入

./a.out --help

输出

all options:
    -a [ –apple ] arg (=10) 苹果的数量
    -o [ –orange ] arg (=20) 橘子的数量
    –address arg 生产地
    –help 计算苹果和橘子的总数量

指定苹果和橘子的数量:

./a.out --apple=8 –orange=20

其输出为:

苹果的数量:8
    橘子的数量:20
    总数量数量:28

仅指定橘子的数量,不指定苹果的数量:

./a.out --orange=20

其输出为:

苹果的数量:10
    橘子的数量:20
    总数量数量:30

可以看到,由于没有输入苹果的数量,所以输出的苹果的数量为我们指定的默认值

指定一个生产地:

./a.out --apple=8 --orange=20 --address=山东

输出:

生产地为:山东
    苹果的数量:8
    橘子的数量:20
    总数量数量:28

指定多个生产地:

./a.out --apple=8 --orange=20 --address=山东 陕西

输出为

生产地为:山东 陕西
    苹果的数量:8
    橘子的数量:20
    总数量数量:28

简写形式的输入:

./a.out -a 8 -o 20 --address=山东

输出:

生产地为:山东
    苹果的数量:8
    橘子的数量:20
    总数量数量:28


boost库中的 program_options的更多相关文章

  1. boost库中sleep方法详解

    博客转载自:https://blog.csdn.net/huang_xw/article/details/8453506 boost库中sleep有两个方法: 1. 这个方法只能在线程中用, 在主线程 ...

  2. 详解boost库中的Message Queue .

    Message Queue(后文简写成MQ或消息队列)是boost库中用来封装进程间通信的一种实现,同一台机器上的进程或线程可以通过消息队列来进行通迅.消息队列中的消息由优先级.消息长度.消息数据三部 ...

  3. 使用Boost库中的组件进行C++内存管理

    C++标准库中的auto_ptr,智能指针,部分的解决了获取资源自动释放的问题 在Boost中,提供了6中智能指针:scoped_ptr, scoped_array, shared_ptr, shar ...

  4. 【Boost】boost库中timer定时器 1

    博客转载自:http://blog.csdn.net/liujiayu2/article/details/50384537 同步Timer asio中提供的timer名为deadline_timer, ...

  5. 【Boost】boost库中timer定时器 2

    博客转载自:http://blog.csdn.net/yockie/article/details/40386145 先跟着boost文档中asio章节的指南中的几个例子学习一下使用: 所有的Asio ...

  6. boost库中thread多线程详解2——mutex与lock

    1. mutex对象类 mutex类主要有两种:独占式与共享式的互斥量.▲ 独占式互斥量:mutex: 独占式的互斥量,是最简单最常用的一种互斥量类型try_mutex: 它是mutex的同义词,为了 ...

  7. 自己实现的Boost库中的lexical_cast随意类型转换

    知道了C++的I/O设施之后.这些就变的非常easy了. 假设你常常使用,时间长了就会有感觉.这个事情是多此一举吗?就当是练习吧,知道原理之后,你会认为用起来更舒畅,更喜欢C++了. #include ...

  8. 在RedHat 7.2中安装boost库

    在RedHat 7.2中安装boost库 环境,其它版本类似 Redhat7.2 64bit boost 1.64.0 步骤 去 boost官网 下载想要版本的.tar.gz,如下图 解压tar -v ...

  9. Boost库安装理解

    Boost安装的安装,以及在VS2013下的使用 1. 为什么要安装? boost是一个开源库,因为开源库可以跨平台,可以通过在不同的“硬件”平台上.所以需要安装的操作. 安装,然后编译生成“静态链接 ...

随机推荐

  1. RSA 汇总

    最近工作中遇到了RSA,这个,以前只是粗略的看了一下,结果,实际使用的时候,各种眼花缭乱啊.现在整理一下RSA有哪些相关知识. 1. RSA算法本身.算法本身的内容实际上是在pkcs#1的标准里面说明 ...

  2. Java多线程编程的常见陷阱

    .在构造函数中启动线程 我在很多代码中都看到这样的问题,在构造函数中启动一个线程,类似这样: public class A{ public A(){ ; ; this.thread=new MyThr ...

  3. LeetCode 链表(旋转链表61)

    /* * 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数. * 构造一个环,对链表进行处理. * *实现原理:先遍历一遍,得出链表长度,注意K可能大于len,之后令k% ...

  4. Apache Maven 3.6.1配置安装

    Apache Maven 3.6.1配置安装 一.下载 maven下载地址:http://maven.apache.org/download.cgi 二.安装 1,解压即可用 2,环境变量配置 MAV ...

  5. tee命令使用

    需求描述: 今天在看nginx内容的过程,遇到了tee这个命令,所以查询了下,在这里记录下使用方法. 操作过程: 1.执行以下的命令 [root@testvm ~]# uname -n | tee h ...

  6. 使用Semaphore同步,经典银行账户问题

    1.新建Account类,使用Semaphore同步增加和减少金额方法. package com.xkzhangsan.semaphorepack.bank; import java.util.con ...

  7. day 04

    今天学些的内容 流程控制 1.在python一般代码执行顺序都从上到下依次解释执行称为顺序结构. 2.然而遇到需要一些条件判断的时候需要选择不同的执行路线去解释执行 这种流程控制称为 分支结构 也可叫 ...

  8. list set map区别及适用场景

    list与Set.Map区别及适用场景   1.List,Set都是继承自Collection接口,Map则不是 2.List特点:元素有放入顺序,元素可重复 ,Set特点:元素无放入顺序,元素不可重 ...

  9. vue-router使用 看着篇就够了

    官网地址:https://router.vuejs.org/zh/ 先来个自我介绍吧,我就是你们口中的路由,我的作用就是告诉你们怎么到达某地,比如你想去一个地方(前提是这个地方是已经存在的)我会查询我 ...

  10. 解决 ImportError: No module named _internal

    参考: My pip is broken. _internal module cannot be imported. #5253 解决 ImportError: No module named _in ...