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