C++?Boost?ProgramOptions超詳細(xì)講解
一、說明
Boost.ProgramOptions 是一個(gè)可以輕松解析命令行選項(xiàng)的庫,例如,控制臺應(yīng)用程序。如果您使用圖形用戶界面開發(fā)應(yīng)用程序,命令行選項(xiàng)通常并不重要。
要使用 Boost.ProgramOptions 解析命令行選項(xiàng),需要以下三個(gè)步驟:
- 定義命令行選項(xiàng)。您給它們命名并指定哪些可以設(shè)置為一個(gè)值。如果命令行選項(xiàng)被解析為鍵/值對,您還可以設(shè)置值的類型——例如,它是字符串還是數(shù)字。
- 使用解析器評估命令行。您可以從 main() 的兩個(gè)參數(shù)獲取命令行,這兩個(gè)參數(shù)通常稱為 argc 和 argv。
- 存儲解析器評估的命令行選項(xiàng)。 Boost.ProgramOptions 提供了一個(gè)派生自 std::map 的類,它將命令行選項(xiàng)保存為名稱/值對。之后,您可以檢查存儲了哪些選項(xiàng)以及它們的值是什么。
二、示例Boost.ProgramOptions
示例 63.1。展示了使用 Boost.ProgramOptions 解析命令行選項(xiàng)的基本方法。
示例 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 中訪問此庫中的所有類和函數(shù)。
使用類 boost::program_options::options_description 來描述命令行選項(xiàng)。這種類型的對象可以寫入諸如 std::cout 之類的流,以顯示可用命令行選項(xiàng)的概覽。傳遞給構(gòu)造函數(shù)的字符串為概覽提供了一個(gè)名稱,作為命令行選項(xiàng)的標(biāo)題。
boost::program_options::options_description 定義了一個(gè)成員函數(shù) add() ,它需要一個(gè) boost::program_options::option_description 類型的參數(shù)。您調(diào)用此函數(shù)來描述每個(gè)命令行選項(xiàng)。示例 63.1 不是為每個(gè)命令行選項(xiàng)調(diào)用此函數(shù),而是調(diào)用成員函數(shù) add_options(),這使得該任務(wù)更容易。
add_options() 返回一個(gè)代表 boost::program_options::options_description 類型對象的代理對象。代理對象的類型無關(guān)緊要。更有趣的是代理對象簡化了許多命令行選項(xiàng)的定義。它使用重載運(yùn)算符 operator(),您可以調(diào)用它來傳遞所需的數(shù)據(jù)以定義命令行選項(xiàng)。此運(yùn)算符返回對同一代理對象的引用,這允許您多次調(diào)用 operator()。
示例 63.1 在代理對象的幫助下定義了三個(gè)命令行選項(xiàng)。第一個(gè)命令行選項(xiàng)是 --help。此選項(xiàng)的說明設(shè)置為“幫助屏幕”。該選項(xiàng)是一個(gè)開關(guān),而不是名稱/值對。您可以在命令行上設(shè)置 --help 或忽略它。無法將 --help 設(shè)置為一個(gè)值。
請注意,傳遞給 operator() 的第一個(gè)字符串是“help,h”。您可以為命令行選項(xiàng)指定簡稱。短名稱必須僅由一個(gè)字母組成,并設(shè)置在逗號之后?,F(xiàn)在可以使用 --help 或 -h 顯示幫助。
除了 --help 之外,還定義了另外兩個(gè)命令行選項(xiàng):--pi 和 --age。這些選項(xiàng)不是開關(guān),它們是名稱/值對。 --pi 和 --age 都應(yīng)設(shè)置為一個(gè)值。
您將指向類型為 boost::program_options::value_semantic 的對象的指針作為第二個(gè)參數(shù)傳遞給 operator() 以將選項(xiàng)定義為名稱/值對。您不需要直接訪問 boost::program_options::value_semantic。您可以使用輔助函數(shù) boost::program_options::value(),它創(chuàng)建一個(gè)類型為 boost::program_options::value_semantic 的對象。 boost::program_options::value() 返回對象的地址,然后您可以使用 operator() 將其傳遞給代理對象。
boost::program_options::value() 是一個(gè)函數(shù)模板,它將命令行選項(xiàng)值的類型作為模板參數(shù)。因此,命令行選項(xiàng) --age 需要一個(gè)整數(shù),而 --pi 需要一個(gè)浮點(diǎn)數(shù)。
從 boost::program_options::value() 返回的對象提供了一些有用的成員函數(shù)。例如,您可以調(diào)用 default_value() 來提供默認(rèn)值。如果未在命令行中使用該選項(xiàng),則示例 63.1 將 --pi 設(shè)置為 3.14。
notifier() 將函數(shù)鏈接到命令行選項(xiàng)的值。然后使用命令行選項(xiàng)的值調(diào)用該函數(shù)。在示例 63.1 中,函數(shù) on_age() 鏈接到 --age。如果命令行選項(xiàng) --age 用于設(shè)置年齡,則年齡將傳遞給 on_age() 并將其寫入標(biāo)準(zhǔn)輸出。
使用 on_age() 等函數(shù)處理值是可選的。您不必使用 notifier(),因?yàn)榭梢酝ㄟ^其他方式訪問值。
定義所有命令行選項(xiàng)后,您可以使用解析器。在示例 63.1 中,輔助函數(shù) boost::program_options::parse_command_line() 被調(diào)用來解析命令行。此函數(shù)采用定義命令行的 argc 和 argv,以及包含選項(xiàng)說明的 desc。 boost::program_options::parse_command_line() 在 boost::program_options::parsed_options 類型的對象中返回解析后的選項(xiàng)。你通常不直接訪問這個(gè)對象。相反,您將它傳遞給 boost::program_options::store(),它將解析的選項(xiàng)存儲在容器中。
示例 63.1 將 vm 作為第二個(gè)參數(shù)傳遞給 boost::program_options::store()。 vm 是 boost::program_options::variables_map 類型的對象。此類派生自類 std::map<std::string, boost::program_options::variable_value>,因此提供與 std::map 相同的成員函數(shù)。例如,您可以調(diào)用 count() 來檢查某個(gè)命令行選項(xiàng)是否已被使用并存儲在容器中。
在示例 63.1 中,在訪問 vm 和調(diào)用 count() 之前,調(diào)用了 boost::program_options::notify()。此函數(shù)觸發(fā)諸如 on_age() 之類的函數(shù),這些函數(shù)使用 notifier() 鏈接到一個(gè)值。如果沒有 boost::program_options::notify(),將不會調(diào)用 on_age()。
vm 可以讓您檢查某個(gè)命令行選項(xiàng)是否存在,還可以讓您訪問命令行選項(xiàng)設(shè)置的值。該值的類型是 boost::program_options::variable_value,一個(gè)在內(nèi)部使用 boost::any 的類。您可以從成員函數(shù) value() 中獲取類型為 boost::any 的對象。
示例 63.1 調(diào)用 as(),而不是 value()。此成員函數(shù)將命令行選項(xiàng)的值轉(zhuǎn)換為作為模板參數(shù)傳遞的類型。 as() 使用 boost::any_cast() 進(jìn)行類型轉(zhuǎn)換。
確保您傳遞給 as() 的類型與命令行選項(xiàng)的類型相匹配。例如,示例 63.1 期望將命令行選項(xiàng) --age 設(shè)置為 int 類型的數(shù)字,因此必須將 int 作為模板參數(shù)傳遞給 as()。
您可以通過多種方式啟動(dòng)示例 63.1。這是一個(gè)例子:
測試
在這種情況下,顯示 Pi: 3.14。因?yàn)?--pi 未在命令行上設(shè)置,所以顯示默認(rèn)值。
此示例使用 --pi 設(shè)置一個(gè)值:
測試 --pi 3.1415
該程序現(xiàn)在顯示 Pi:3.1415。
這個(gè)例子也傳遞了一個(gè)年齡:
測試 --pi 3.1415 --age 29
輸出現(xiàn)在是 On age: 29 和 Age: 29。第一行是在調(diào)用 boost::program_options::notify() 時(shí)寫入的;這會觸發(fā) on_age() 的執(zhí)行。 --pi 沒有輸出,因?yàn)槌绦蚴褂?else if 語句,如果未設(shè)置 --age 則僅顯示用 --pi 設(shè)置的值。
此示例顯示幫助:
測試 -h
您可以獲得所有命令行選項(xiàng)的完整概述:
Options: -h [ --help ] Help screen --pi arg (=3.1400001) Pi --age arg Age
如您所見,幫助可以以兩種不同的方式顯示,因?yàn)闉樵撁钚羞x項(xiàng)定義了一個(gè)短名稱。對于 --pi,顯示默認(rèn)值。命令行選項(xiàng)及其描述會自動(dòng)格式化。您只需將類型為 boost::program_options::options_description 的對象寫入標(biāo)準(zhǔn)輸出,如示例 63.1 所示。
現(xiàn)在,像這樣開始這個(gè)例子:
測試——年齡
輸出如下:
缺少選項(xiàng)“--age”所需的參數(shù)。
因?yàn)槲丛O(shè)置 --age,boost::program_options::parse_command_line() 中使用的解析器會拋出 boost::program_options::error 類型的異常。捕獲異常,并將錯(cuò)誤消息寫入標(biāo)準(zhǔn)輸出。
boost::program_options::error 派生自 std::logic_error。 Boost.ProgramOptions 定義了額外的異常,它們都派生自 boost::program_options::error。其中一個(gè)異常是 boost::program_options::invalid_syntax,如果您沒有為 --age 提供值,它就是在示例 63.1 中拋出的異常。
示例 63.2 引入了更多可用于 Boost.ProgramOptions 的配置設(shè)置。
示例 63.2。使用 Boost.ProgramOptions 的特殊配置設(shè)置
#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';
}
}設(shè)置配置后,在解析器上調(diào)用 run()。此成員函數(shù)在 boost::program_options::parsed_options 類型的對象中返回解析的命令行選項(xiàng),您可以將其傳遞給 boost::program_options::store() 以將選項(xiàng)存儲在 vm 中。
在代碼的后面,示例 63.2 再次訪問 vm 以評估命令行選項(xiàng)。只有對 boost::program_options::collect_unrecognized() 的調(diào)用是新的。此函數(shù)為命令行選項(xiàng) --unreg 調(diào)用。該函數(shù)需要一個(gè) boost::program_options::parsed_options 類型的對象,它由 run() 返回。它在 std::vector<std::string> 中返回所有未知的命令行選項(xiàng)。例如,如果您使用 test --unreg --abc 啟動(dòng)程序,--abc 將寫入標(biāo)準(zhǔn)輸出。
當(dāng) boost::program_options::exclude_positional 作為第二個(gè)參數(shù)傳遞給 boost::program_options::collect_unrecognized() 時(shí),位置選項(xiàng)將被忽略。對于示例 63.2,這無關(guān)緊要,因?yàn)闆]有定義位置選項(xiàng)。但是,boost::program_options::collect_unrecognized() 需要此參數(shù)。
示例 63.3 說明了位置選項(xiàng)。
示例 63.3。 Boost.ProgramOptions 的位置選項(xiàng)
#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';
}
}示例 63.3 使用類 boost::program_options::positional_options_description 將 --phone 定義為位置選項(xiàng)。此類提供成員函數(shù) add(),它需要傳遞命令行選項(xiàng)的名稱和位置。該示例傳遞“phone”和 -1。
使用位置選項(xiàng),可以在命令行上設(shè)置值,而無需使用命令行選項(xiàng)。您可以像這樣啟動(dòng)示例 63.3:
測試 123 456
即使未使用 --phone,123 和 456 也會被識別為電話號碼。
在類型為 boost::program_options::positional_options_description 的對象上調(diào)用 add() 會將命令行上的值分配給使用位置編號的命令行選項(xiàng)。當(dāng)使用命令行測試 123 456 調(diào)用示例 63.3 時(shí),123 的位置編號為 0,456 的位置編號為 1。示例 63.3 將 -1 傳遞給 add(),它將所有值 - 123 和 456 - 分配給 - -電話。如果您更改示例 63.3 以將值 0 傳遞給 add(),則只有 123 會被識別為電話號碼。如果將 1 傳遞給 add(),則只會識別 456。
pos_desc 與 positional() 一起傳遞給解析器。這就是解析器如何知道哪些命令行選項(xiàng)是位置的。
請注意,您必須確保定義了位置選項(xiàng)。例如,在示例 63.3 中,“phone”只能傳遞給 add(),因?yàn)?--phone 的定義已經(jīng)存在于 desc 中。
在之前的所有示例中,Boost.ProgramOptions 用于解析命令行選項(xiàng)。但是,該庫也支持從文件加載配置選項(xiàng)。如果必須重復(fù)設(shè)置相同的命令行選項(xiàng),這會很有用。
示例 63.4。從配置文件加載選項(xiàng)
#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';
}
}示例 63.4 使用了兩個(gè)類型為 boost::program_options::options_description 的對象。 generalOptions 定義必須在命令行上設(shè)置的選項(xiàng)。 fileOptions 定義可以從配置文件加載的選項(xiàng)。
不必使用類型為 boost::program_options::options_description 的兩個(gè)不同對象來定義選項(xiàng)。如果命令行和文件的選項(xiàng)集相同,則可以只使用一個(gè)。在示例 63.4 中,分隔選項(xiàng)是有意義的,因?yàn)槟幌朐试S在配置文件中設(shè)置 --help。如果允許并且用戶將該選項(xiàng)放入配置文件中,則程序每次都會顯示幫助屏幕。
示例 63.4 從配置文件加載 --age。您可以將配置文件的名稱作為命令行選項(xiàng)傳遞。出于這個(gè)原因,在此示例中,--config 是在 generalOptions 中定義的。
在使用 boost::program_options::parse_command_line() 解析命令行選項(xiàng)并存儲在 vm 中后,該示例檢查是否設(shè)置了 --config。如果是,則使用 std::ifstream 打開配置文件。 std::ifstream 對象與描述選項(xiàng)的文件選項(xiàng)一起傳遞給函數(shù) boost::program_options::parse_config_file()。 boost::program_options::parse_config_file() 做與 boost::program_options::parse_command_line() 相同的事情,并在 boost::program_options::parsed_options 類型的對象中返回解析后的選項(xiàng)。該對象被傳遞給 boost::program_options::store() 以將解析的選項(xiàng)存儲在 vm 中。
如果您創(chuàng)建一個(gè)名為 config.txt 的文件,將 age=29 放入該文件,然后執(zhí)行下面的命令行,您將得到顯示的結(jié)果。
測試 --config config.txt
輸出如下:
Your age is: 29
如果您在命令行和配置文件中支持相同的選項(xiàng),您的程序可能會解析相同的選項(xiàng)兩次——一次使用 boost::program_options::parse_command_line(),一次使用 boost::program_options::parse_config_file()。函數(shù)調(diào)用的順序決定了您將在 vm 中找到哪個(gè)值。一旦命令行選項(xiàng)的值存儲在 vm 中,該值將不會被覆蓋。該值是由命令行上的選項(xiàng)還是在配置文件中設(shè)置的,僅取決于您調(diào)用 store() 函數(shù)的順序。
Boost.ProgramOptions 還定義了函數(shù) boost::program_options::parse_environment(),可用于從環(huán)境變量加載選項(xiàng)。類 boost::environment_iterator 允許您迭代環(huán)境變量。
到此這篇關(guān)于C++ Boost ProgramOptions超詳細(xì)講解的文章就介紹到這了,更多相關(guān)C++ Boost ProgramOptions內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++11右值引用和轉(zhuǎn)發(fā)型引用教程詳解
這篇文章主要介紹了C++11右值引用和轉(zhuǎn)發(fā)型引用教程詳解,需要的朋友可以參考下2018-03-03
Vs?Code中C/C++配置launch.json和tasks.json文件詳細(xì)步驟
使用VSCode開發(fā)C/C++程序,需要配置tasks.json/launch.json,下面這篇文章主要給大家介紹了關(guān)于Vs?Code中C/C++配置launch.json和tasks.json文件的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01
用C# 控制Windows系統(tǒng)音量的實(shí)現(xiàn)方法
本篇文章是對使用C#控制Windows系統(tǒng)音量的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05

