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