【BOOST C++ 19 应用库】(2)Boost.ProgramOptions

news/2024/4/25 20:44:57/文章来源:https://blog.csdn.net/gongdiwudu/article/details/128060940

一、说明

Boost.ProgramOptions

Boost.ProgramOptions 是一个可以轻松解析命令行选项的库,例如,控制台应用程序。如果您使用图形用户界面开发应用程序,命令行选项通常并不重要。

要使用 Boost.ProgramOptions 解析命令行选项,需要以下三个步骤:

  1. 定义命令行选项。您给它们命名并指定哪些可以设置为一个值。如果命令行选项被解析为键/值对,您还可以设置值的类型——例如,它是字符串还是数字。

  2. 使用解析器评估命令行。您可以从 main() 的两个参数获取命令行,这两个参数通常称为 argc 和 argv。

  3. 存储解析器评估的命令行选项。 Boost.ProgramOptions 提供了一个派生自 std::map 的类,它将命令行选项保存为名称/值对。之后,您可以检查存储了哪些选项以及它们的值是什么。

二、示例Boost.ProgramOptions

Example 63.1

示例 63.1。展示了使用 Boost.ProgramOptions 解析命令行选项的基本方法。

示例 63.1。 Boost.ProgramOptions 的基本方法

#include <boost/program_options.hpp>
#include <iostream>using namespace boost::program_options;void on_age(int age)
{std::cout << "On age: " << age << '\n';
}int main(int argc, const char *argv[])
{try{options_description desc{"Options"};desc.add_options()("help,h", "Help screen")("pi", value<float>()->default_value(3.14f), "Pi")("age", value<int>()->notifier(on_age), "Age");variables_map vm;store(parse_command_line(argc, argv, desc), vm);notify(vm);if (vm.count("help"))std::cout << desc << '\n';else if (vm.count("age"))std::cout << "Age: " << vm["age"].as<int>() << '\n';else if (vm.count("pi"))std::cout << "Pi: " << vm["pi"].as<float>() << '\n';}catch (const error &ex){std::cerr << ex.what() << '\n';}
}

        要使用 Boost.ProgramOptions,请包含头文件 boost/program_options.hpp。您可以在命名空间 boost::program_options 中访问此库中的所有类和函数。

        使用类 boost::program_options::options_description 来描述命令行选项。这种类型的对象可以写入诸如 std::cout 之类的流,以显示可用命令行选项的概览。传递给构造函数的字符串为概览提供了一个名称,作为命令行选项的标题。

        boost::program_options::options_description 定义了一个成员函数 add() ,它需要一个 boost::program_options::option_description 类型的参数。您调用此函数来描述每个命令行选项。示例 63.1 不是为每个命令行选项调用此函数,而是调用成员函数 add_options(),这使得该任务更容易。

        add_options() 返回一个代表 boost::program_options::options_description 类型对象的代理对象。代理对象的类型无关紧要。更有趣的是代理对象简化了许多命令行选项的定义。它使用重载运算符 operator(),您可以调用它来传递所需的数据以定义命令行选项。此运算符返回对同一代理对象的引用,这允许您多次调用 operator()。

Example 63.1

示例 63.1 在代理对象的帮助下定义了三个命令行选项。第一个命令行选项是 --help。此选项的说明设置为“帮助屏幕”。该选项是一个开关,而不是名称/值对。您可以在命令行上设置 --help 或忽略它。无法将 --help 设置为一个值。请注意,传递给 operator() 的第一个字符串是“help,h”。您可以为命令行选项指定简称。短名称必须仅由一个字母组成,并设置在逗号之后。现在可以使用 --help 或 -h 显示帮助。除了 --help 之外,还定义了另外两个命令行选项:--pi 和 --age。这些选项不是开关,它们是名称/值对。 --pi 和 --age 都应设置为一个值。您将指向类型为 boost::program_options::value_semantic 的对象的指针作为第二个参数传递给 operator() 以将选项定义为名称/值对。您不需要直接访问 boost::program_options::value_semantic。您可以使用辅助函数 boost::program_options::value(),它创建一个类型为 boost::program_options::value_semantic 的对象。 boost::program_options::value() 返回对象的地址,然后您可以使用 operator() 将其传递给代理对象。boost::program_options::value() 是一个函数模板,它将命令行选项值的类型作为模板参数。因此,命令行选项 --age 需要一个整数,而 --pi 需要一个浮点数。从 boost::program_options::value() 返回的对象提供了一些有用的成员函数。例如,您可以调用 default_value() 来提供默认值。如果未在命令行中使用该选项,则示例 63.1 将 --pi 设置为 3.14。
notifier() 将函数链接到命令行选项的值。然后使用命令行选项的值调用该函数。在示例 63.1 中,函数 on_age() 链接到 --age。如果命令行选项 --age 用于设置年龄,则年龄将传递给 on_age() 并将其写入标准输出。使用 on_age() 等函数处理值是可选的。您不必使用 notifier(),因为可以通过其他方式访问值。定义所有命令行选项后,您可以使用解析器。在示例 63.1 中,辅助函数 boost::program_options::parse_command_line() 被调用来解析命令行。此函数采用定义命令行的 argc 和 argv,以及包含选项说明的 desc。 boost::program_options::parse_command_line() 在 boost::program_options::parsed_options 类型的对象中返回解析后的选项。你通常不直接访问这个对象。相反,您将它传递给 boost::program_options::store(),它将解析的选项存储在容器中。示例 63.1 将 vm 作为第二个参数传递给 boost::program_options::store()。 vm 是 boost::program_options::variables_map 类型的对象。此类派生自类 std::map<std::string, boost::program_options::variable_value>,因此提供与 std::map 相同的成员函数。例如,您可以调用 count() 来检查某个命令行选项是否已被使用并存储在容器中。在示例 63.1 中,在访问 vm 和调用 count() 之前,调用了 boost::program_options::notify()。此函数触发诸如 on_age() 之类的函数,这些函数使用 notifier() 链接到一个值。如果没有 boost::program_options::notify(),将不会调用 on_age()。vm 可以让您检查某个命令行选项是否存在,还可以让您访问命令行选项设置的值。该值的类型是 boost::program_options::variable_value,一个在内部使用 boost::any 的类。您可以从成员函数 value() 中获取类型为 boost::any 的对象。示例 63.1 调用 as(),而不是 value()。此成员函数将命令行选项的值转换为作为模板参数传递的类型。 as() 使用 boost::any_cast() 进行类型转换。确保您传递给 as() 的类型与命令行选项的类型相匹配。例如,示例 63.1 期望将命令行选项 --age 设置为 int 类型的数字,因此必须将 int 作为模板参数传递给 as()。您可以通过多种方式启动示例 63.1。这是一个例子:

测试

在这种情况下,显示 Pi: 3.14。因为 --pi 未在命令行上设置,所以显示默认值。

此示例使用 --pi 设置一个值:

测试 --pi 3.1415

该程序现在显示 Pi:3.1415。

这个例子也传递了一个年龄:

测试 --pi 3.1415 --age 29

输出现在是 On age: 29 和 Age: 29。第一行是在调用 boost::program_options::notify() 时写入的;这会触发 on_age() 的执行。 --pi 没有输出,因为程序使用 else if 语句,如果未设置 --age 则仅显示用 --pi 设置的值。

此示例显示帮助:

测试 -h

您可以获得所有命令行选项的完整概述:

Options: -h [ --help ]         Help screen --pi arg (=3.1400001) Pi --age arg             Age
如您所见,帮助可以以两种不同的方式显示,因为为该命令行选项定义了一个短名称。对于 --pi,显示默认值。命令行选项及其描述会自动格式化。您只需将类型为 boost::program_options::options_description 的对象写入标准输出,如示例 63.1 所示。现在,像这样开始这个例子:测试——年龄输出如下:缺少选项“--age”所需的参数。因为未设置 --age,boost::program_options::parse_command_line() 中使用的解析器会抛出 boost::program_options::error 类型的异常。捕获异常,并将错误消息写入标准输出。boost::program_options::error 派生自 std::logic_error。 Boost.ProgramOptions 定义了额外的异常,它们都派生自 boost::program_options::error。其中一个异常是 boost::program_options::invalid_syntax,如果您没有为 --age 提供值,它就是在示例 63.1 中抛出的异常。示例 63.2 引入了更多可用于 Boost.ProgramOptions 的配置设置。示例 63.2。使用 Boost.ProgramOptions 的特殊配置设置
#include <boost/program_options.hpp>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>using namespace boost::program_options;void to_cout(const std::vector<std::string> &v)
{std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>{std::cout, "\n"});
}int main(int argc, const char *argv[])
{try{int age;options_description desc{"Options"};desc.add_options()("help,h", "Help screen")("pi", value<float>()->implicit_value(3.14f), "Pi")("age", value<int>(&age), "Age")("phone", value<std::vector<std::string>>()->multitoken()->zero_tokens()->composing(), "Phone")("unreg", "Unrecognized options");command_line_parser parser{argc, argv};parser.options(desc).allow_unregistered().style(command_line_style::default_style |command_line_style::allow_slash_for_short);parsed_options parsed_options = parser.run();variables_map vm;store(parsed_options, vm);notify(vm);if (vm.count("help"))std::cout << desc << '\n';else if (vm.count("age"))std::cout << "Age: " << age << '\n';else if (vm.count("phone"))to_cout(vm["phone"].as<std::vector<std::string>>());else if (vm.count("unreg"))to_cout(collect_unrecognized(parsed_options.options,exclude_positional));else if (vm.count("pi"))std::cout << "Pi: " << vm["pi"].as<float>() << '\n';}catch (const error &ex){std::cerr << ex.what() << '\n';}
}

Example 63.2

        设置配置后,在解析器上调用 run()。此成员函数在 boost::program_options::parsed_options 类型的对象中返回解析的命令行选项,您可以将其传递给 boost::program_options::store() 以将选项存储在 vm 中。

        在代码的后面,示例 63.2 再次访问 vm 以评估命令行选项。只有对 boost::program_options::collect_unrecognized() 的调用是新的。此函数为命令行选项 --unreg 调用。该函数需要一个 boost::program_options::parsed_options 类型的对象,它由 run() 返回。它在 std::vector<std::string> 中返回所有未知的命令行选项。例如,如果您使用 test --unreg --abc 启动程序,--abc 将写入标准输出。

        当 boost::program_options::exclude_positional 作为第二个参数传递给 boost::program_options::collect_unrecognized() 时,位置选项将被忽略。对于示例 63.2,这无关紧要,因为没有定义位置选项。但是,boost::program_options::collect_unrecognized() 需要此参数。

        示例 63.3 说明了位置选项。

        示例 63.3。 Boost.ProgramOptions 的位置选项

#include <boost/program_options.hpp>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>using namespace boost::program_options;void to_cout(const std::vector<std::string> &v)
{std::copy(v.begin(), v.end(),std::ostream_iterator<std::string>{std::cout, "\n"});
}int main(int argc, const char *argv[])
{try{options_description desc{"Options"};desc.add_options()("help,h", "Help screen")("phone", value<std::vector<std::string>>()->multitoken()->zero_tokens()->composing(), "Phone");positional_options_description pos_desc;pos_desc.add("phone", -1);command_line_parser parser{argc, argv};parser.options(desc).positional(pos_desc).allow_unregistered();parsed_options parsed_options = parser.run();variables_map vm;store(parsed_options, vm);notify(vm);if (vm.count("help"))std::cout << desc << '\n';else if (vm.count("phone"))to_cout(vm["phone"].as<std::vector<std::string>>());}catch (const error &ex){std::cerr << ex.what() << '\n';}
}

Example 63.3 

示例 63.3 使用类 boost::program_options::positional_options_description 将 --phone 定义为位置选项。此类提供成员函数 add(),它需要传递命令行选项的名称和位置。该示例传递“phone”和 -1。使用位置选项,可以在命令行上设置值,而无需使用命令行选项。您可以像这样启动示例 63.3:测试 123 456即使未使用 --phone,123 和 456 也会被识别为电话号码。在类型为 boost::program_options::positional_options_description 的对象上调用 add() 会将命令行上的值分配给使用位置编号的命令行选项。当使用命令行测试 123 456 调用示例 63.3 时,123 的位置编号为 0,456 的位置编号为 1。示例 63.3 将 -1 传递给 add(),它将所有值 - 123 和 456 - 分配给 - -电话。如果您更改示例 63.3 以将值 0 传递给 add(),则只有 123 会被识别为电话号码。如果将 1 传递给 add(),则只会识别 456。pos_desc 与 positional() 一起传递给解析器。这就是解析器如何知道哪些命令行选项是位置的。请注意,您必须确保定义了位置选项。例如,在示例 63.3 中,“phone”只能传递给 add(),因为 --phone 的定义已经存在于 desc 中。在之前的所有示例中,Boost.ProgramOptions 用于解析命令行选项。但是,该库也支持从文件加载配置选项。如果必须重复设置相同的命令行选项,这会很有用。示例 63.4。从配置文件加载选项
#include <boost/program_options.hpp>
#include <string>
#include <fstream>
#include <iostream>using namespace boost::program_options;int main(int argc, const char *argv[])
{try{options_description generalOptions{"General"};generalOptions.add_options()("help,h", "Help screen")("config", value<std::string>(), "Config file");options_description fileOptions{"File"};fileOptions.add_options()("age", value<int>(), "Age");variables_map vm;store(parse_command_line(argc, argv, generalOptions), vm);if (vm.count("config")){std::ifstream ifs{vm["config"].as<std::string>().c_str()};if (ifs)store(parse_config_file(ifs, fileOptions), vm);}notify(vm);if (vm.count("help"))std::cout << generalOptions << '\n';else if (vm.count("age"))std::cout << "Your age is: " << vm["age"].as<int>() << '\n';}catch (const error &ex){std::cerr << ex.what() << '\n';}
}

Example 63.4 

示例 63.4 使用了两个类型为 boost::program_options::options_description 的对象。 generalOptions 定义必须在命令行上设置的选项。 fileOptions 定义可以从配置文件加载的选项。不必使用类型为 boost::program_options::options_description 的两个不同对象来定义选项。如果命令行和文件的选项集相同,则可以只使用一个。在示例 63.4 中,分隔选项是有意义的,因为您不想允许在配置文件中设置 --help。如果允许并且用户将该选项放入配置文件中,则程序每次都会显示帮助屏幕。示例 63.4 从配置文件加载 --age。您可以将配置文件的名称作为命令行选项传递。出于这个原因,在此示例中,--config 是在 generalOptions 中定义的。在使用 boost::program_options::parse_command_line() 解析命令行选项并存储在 vm 中后,该示例检查是否设置了 --config。如果是,则使用 std::ifstream 打开配置文件。 std::ifstream 对象与描述选项的文件选项一起传递给函数 boost::program_options::parse_config_file()。 boost::program_options::parse_config_file() 做与 boost::program_options::parse_command_line() 相同的事情,并在 boost::program_options::parsed_options 类型的对象中返回解析后的选项。该对象被传递给 boost::program_options::store() 以将解析的选项存储在 vm 中。如果您创建一个名为 config.txt 的文件,将 age=29 放入该文件,然后执行下面的命令行,您将得到显示的结果。测试 --config config.txt输出如下:
Your age is: 29

        如果您在命令行和配置文件中支持相同的选项,您的程序可能会解析相同的选项两次——一次使用 boost::program_options::parse_command_line(),一次使用 boost::program_options::parse_config_file()。函数调用的顺序决定了您将在 vm 中找到哪个值。一旦命令行选项的值存储在 vm 中,该值将不会被覆盖。该值是由命令行上的选项还是在配置文件中设置的,仅取决于您调用 store() 函数的顺序。

        Boost.ProgramOptions 还定义了函数 boost::program_options::parse_environment(),可用于从环境变量加载选项。类 boost::environment_iterator 允许您迭代环境变量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_38987.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何从报表控件FastReport .NET中连接到 PostgreSQL 数据库?

FastReport.NET官方版下载 Fastreport是目前世界上主流的图表控件&#xff0c;具有超高性价比&#xff0c;以更具成本优势的价格&#xff0c;便能提供功能齐全的报表解决方案&#xff0c;连续三年蝉联全球文档创建组件和库的“ Top 50 Publishers”奖。 慧都科技是Fast Repor…

mysql索引类别和失效场景

首先&#xff0c;我们为什么要使用索引&#xff0c;索引有什么作用呢&#xff1f; 索引可以用来快速查询数据表中有某一特定值的记录&#xff0c;大大加快数据的查询速度&#xff1b;在列上创建了索引之后&#xff0c;查找数据时可以直接根据该列上的索引找到对应记录行的位置…

YOLO X 改进详解

YOLO X 主要改进&#xff1a; Anchor-Free: FCOSDecoupled detection headAdvanced label assigning strategy Network structure improvement Decoupled detection head 对比于YOLO V5, YOLO X 在detection head上有了改进。YOLO V5中&#xff0c;检测头是通过卷积同时预…

视频编解码 - RTP 与 RTCP

目录 RTP 实时传输协议 RTCP协议 将H264 RTP打包 RTP 实时传输协议 音视频数据传输&#xff0c;先将原始数据经过编码压缩后&#xff0c;将码流打包成一个个RTP包&#xff0c;再将码流传输到接收端。 打包的作用 接收端要正确地使用这些音视频编码数据&#xff0c;不仅仅需…

JaVers:自动化数据审计

在开发应用程序时&#xff0c;我们经常需要存储有关数据如何随时间变化的信息。此信息可用于更轻松地调试应用程序并满足设计要求。在本文中&#xff0c;我们将讨论 JaVers 工具&#xff0c;该工具允许您通过记录数据库实体状态的更改来自动执行此过程。 Javers如何工作&#x…

vue Router

Vue项目各文件含义 1.src文件夹 是我们真正敲代码的文件夹&#xff0c; 2.assets放静态资源 3.components放组件 4.App.vue主组件 5.main.js项目的入口文件 Vue Router 在router/index.js路由文件中配置路由&#xff0c;设置路由跳转规则 import Vue from vue import Vu…

android Framework 中用到了哪些跨进程通信方式?

文章目录Linux 有哪些跨进程的通信方式&#xff1f;管道本地 Socket共享内存信号Linux 有哪些跨进程的通信方式&#xff1f; Binder 机制是Android基于Linux的一种独特的IPC机制。我们常用的AMS&#xff0c;PMS 等都是通过Binder机制来完成跨进程通信的&#xff0c;那么除了Bin…

【并发】深入理解Java线程的底层原理

线程基础知识 线程与进程 进程 操作系统会以进程为单位&#xff0c;分配系统资源&#xff08;CPU时间片、内存等资源&#xff09;&#xff0c;进程是资源分配的最小单位。 当一个程序被运行&#xff0c;从磁盘加载这个程序的代码至内存&#xff0c;这时就开启了一个进程。 线…

使用 Mason 创建自己的 Flutter brick

使用 Mason 创建自己的 Flutter brick 原文 https://medium.com/gytworkz/create-your-own-flutter-brick-using-mason-7abc70d0324e 前言 谁不喜欢用最少的努力完成大部分事情呢&#xff1f;我当然知道! &#xff01;Mason 帮我完成了几个简单的步骤。 在本文中&#xff0c;我…

Redis——》数据类型:List(列表)

推荐链接&#xff1a; 总结——》【Java】 总结——》【Mysql】 总结——》【Redis】 总结——》【Spring】 总结——》【SpringBoot】 总结——》【MyBatis、MyBatis-Plus】 Redis——》数据类型&#xff1a;List&#xff08;列表&#xff09;一、简介…

复现黑客在后门中藏匿后门

PHP实现在后门中藏匿后门 在攻击渗透的时候会传入shell后门方便进行远控。其中的后门包括多种类型&#xff0c;大马是功能最全的直接提供了可视化的界面方便攻击者进行提权、扫描、上传等一系列的操作。 但有很多hacker不讲武德&#xff0c;在写好的大马中藏入自己的后门&…

VBA Regex 正则表达式应用介绍

. VBA正则表达式介绍 正则表达式或 RegEx 用于在字符串中查找特定的字符。 本文将展示一个 VBA RegEx 示例,并演示为什么在 VBA 中使用正则表达式如此强大。 正则表达式是一个比较大的话题,关于这方面的书很多。 同时也是一个让许多人感到害怕的话题,因为它的语法比较神秘和…

C++入门笔记

C 入门笔记Functions in CC header Files下面主要是我学习C的一个笔记&#xff0c;记录学习中遇到的一些重点事项。下面是视频的连接https://www.bilibili.com/video/BV1Ay4y1i7Z6/?p10&spm_id_from333.1007.top_right_bar_window_history.content.click&vd_sourcee6e…

记录--两行CSS让页面提升了近7倍渲染性能!

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 前言 对于前端人员来讲&#xff0c;最令人头疼的应该就是页面性能了&#xff0c;当用户在访问一个页面时&#xff0c;总是希望它能够快速呈现在眼前并且是可交互状态。如果页面加载过慢&#xff0c;你…

第四章. Pandas进阶—时间序列

第四章. Pandas进阶 4.9 时间序列 1.重采样&#xff08;resample&#xff09; 在Pandas中&#xff0c;对时间序列频率的调整称为重采样&#xff0c;即时间序列从一个频率转换到另一个频率的过程&#xff0c;由周统计变成月统计 1).语法&#xff1a; 4.8章 第4点 已介绍过&…

MySQL数据库行级锁之间隙锁、临键锁

间隙锁 默认情况下&#xff0c;InnoDB在 REPEATABLE READ事务隔离级别运行&#xff0c;InnoDB使用 next-key 锁进行搜索和索引扫描&#xff0c;以防止幻读。 索引上的等值查询(唯一索引)&#xff0c;给不存在的记录加锁时, 优化为间隙锁 。索引上的等值查询(非唯一普通索引)&…

如果把网络原理倒过来看,从无到有,一切如此清晰(下)

人生若只如初见。 前言 当我在台灯下&#xff0c;听着远隔17年前五月天的歌&#xff0c;而在数日后&#xff0c;我的文字也会纵使相隔万里远的来到你的屏幕前&#xff0c;就觉得这一切妙不可言。 OSI 网络七层模型 《如果把网络原理倒过来看&#xff0c;从无到有&#xff0c…

Seal库官方示例(二):encoders.cpp解析

补充一个常用的SIMD操作原理 图片来自的Hang Shao的文章。 完整代码 这个代码主要功能是编码明文&#xff0c;使得能够使用更加完整的明文多项式&#xff08;前一个只用到了一个多项式的常量&#xff09;&#xff0c;也就是SIMD操作。主要包含了两个部分&#xff0c;一个是BG…

HLS + ffmpeg 实现动态码流视频服务

一、简介 如下图&#xff0c;包含三部分&#xff0c;右边一列为边缘节点&#xff1b;中间一列代表数据中心&#xff1b;左边一列是项目为客户提供的一系列web管理工具&#xff1a; 具体来说在我们项目中有一堆边缘节点&#xff0c;每个节点上部署一台强大的GPU服务器及N个网络…

精彩回顾 | 苏州农商银行新一代云原生信息科技架构体系实践

11月18日&#xff0c;2022年第五届中国金融科技产业大会暨第四届中新&#xff08;苏州&#xff09;数字金融应用博览会“基础软件与云原生系统软件”分论坛成功举办。该论坛由由中国计算机学会CTO CLUB&#xff08;苏州&#xff09;承办&#xff0c;江苏省金融科技云原生融合创…