跨平台的命令行参数工具 -- boost program_oprations
1 例子
下例展示了 program_oprations 的基本用法:为程序定义了 3 个参数: help, host, port . 其中 host 与 port 分别定义了简写 h ,p 。host 是必填项, port 是有缺省值(80)的选填项,当 port 有输入时使用输入项,否则使用缺省值 ,当输入了错误的参数时会输出错误信息。
1 |
|
测试效果:
1 | >testBoostProgramOptions.exe |
progma_options 库由三部分组成:
-
descrition, 描述组件,用于描述允许的参数及这些参数的值。 -
parser, 解析组件,用于解析输入的参数与值 -
storage, 存储组件, 它将解析器的输出转换成 字符串表示的健与 C++ 类型的值的 map, 并提供了访问这些值的接口。
对于上例来说, program_options 所做的事情,就是使用 options_description 描述了我们期望的参数,使用 parse_command_line 解析了输入参数并使用 store 将参数存储在 variables_map 中。当我们需要使用某个参数时直接从 variables_map 中获取。
2 description 描述组件
描述组件中有三个重要的类 : option_description, value_semantic 和 options_description . 前两个类组和使用来描述一个参数, option_description 包含了参数的 名称 ,描述 , 以及一个指向 value_semantic 对象的指针,这个指针对象定义了参数值的类型、可被解析的值、缺省值等信息。 而 options_description 则是 option_description 的容器。
一般地,我们添加一个参数时会先创建一个 option_description 对象,再使用 options_description 的 add 方法将参数添加到容器中:
1 | auto descHost = boost::shared_ptr<program_options::option_description>("host", program_options::value<std::string>()->required(), "host name"); |
如果参数比较多的话,使用这种方法就比较麻烦了。所以 boost 有特别的添加技巧:
1 | program_options::options_description desc("Allowed options"); |
这看起来有点怪怪的,实际上这是对 operator( ) 操作符重载的灵活运用。 options_description.add_options() 返回 options_description_easy_init 类的实例,该类重载了 “( )” 操作符,它模拟了 option_description 的构造函数,接收参数信息构造描述信息对象,添加到描述信息容器中,并返回其对象本身的引用,使其可以再次使用 “( )” 操作符来添加描述信息。
一个 option_description 实例可以分成两个部分: 语法 syntactic 和 语义 semantic 。语法信息规定用户输入参数的形式以及解析器解析的方式,包含参数名称与参数可以使用的符号(token) 的数量, 解析器会使用它将符号组成 (参数名,参数值) 这种形式的键值对,其中参数值是一组字符串( std::vector<std::string> ); 而语义信息则负责将参数值转换成合适的 C++ 类型。
2.1 语法信息
语法信息由 boost::program_options::options_description 类 和 boost::program_options::value_semantic 类的一些方法提供。句法信息包括:
-
参数名称用于在程序中做变量标识 -
参数描述用于给用户以提示 -
选项值可用的 token 数将在解析时使用
如下示例:
1 | options_description desc; |
这个示例中, help 不接受任何 token, compression 接收一个 token, verbose 可接受 0 个或 1 个 token, email 可以接受多个 token. 用户可以使用如下命令行:
1 | test --help --compression 10 --verbose --email beadle@mars beadle2@mars |
2.2 语义信息
语义信息完全由 boost::program_options::value_semantic 类提供。 如下示例:
1 | options_description desc; |
可以使用如下命令行:
1 | test --email a@b.com --compression 2 --email c@b.com |
在此例中, compression 将被解析成 2 , 如果没有输入此参数,那么 compression 将使用缺省值 10 。 而 email 参数则可以由多个值组合而成。
2.3 位置信息
位置参数是一种特殊的参数。如:
1 | cat /etc/passwd |
这里 /etc/passwd 是没有参数名的。 当然,向前文一样,给它一个参数名也是可以的:
1 | cat --input-file=/etc/passwd |
但 boost 提供了更优雅的解决方法: positional_options_description 类。该类可以指定:
-
允许使用多少个位置参数
-
每个位置参数的名称
-
每个位置参数的众多参数中的位置
如:
1 | positional_options_description pd; |
例中允许使用两个位置参数,第一个位置参数是参数中的第2个参数,名称为 “output-file”, 第二个位置参数是参数中的倒数第一个参数,其名称为 “input-file”
3 parsers 解析器
顾名思义,解析器的作用就是将输入的命令行解析成程序可用的 (name,value) 键值对。由前几节可以知道,这个解析器依赖的解析规则是由 描述组件 来确定的。如果不符合描述则会抛出异常。除了通过一般的描述信息来解析,还有以下几种特殊的情况:
-
参数名称使用了
简写(或称 =“别名”= ) -
一个参数名有多个参数值的(如上例中的 email )
-
命令行中包含了
positional信息的,见上节内容
常用的解析方法有:
-
program_options::parse_command_line(),解析命令行 -
program_options::parse_config_file(), 解析配置文件 -
program_options::parse_environment(), 解析环境变量
3.1 Configuration file parser
parse_config_file 方法可以解析类似 INI 风格的配置文件。这种风格以行为单位,一行即为一组参数。当然,还有两种特殊情况:
-
以括号
[ ]修饰的行 ,表示一个新的 section -
以
#修饰的注释, 从#符号开始到行结束,都为注释
例如:
1 | host=wandoer.com #host_name |
这些配置与下面的配置是等价的:
1 | host=wandoer.com |
//待续