使用Boost库程序选项的必需和可选参数

我正在使用Boost程序选项库来parsing命令行参数。

我有以下要求:

  1. 一旦提供“帮助”,所有其他选项都是可选的;
  2. 一旦“帮助”没有提供,所有其他选项是必需的。

我如何处理这个? 这是我的代码处理这个,我发现它是非常多余的,我认为必须有一个容易做的,对吧?

#include <boost/program_options.hpp> #include <iostream> #include <sstream> namespace po = boost::program_options; bool process_command_line(int argc, char** argv, std::string& host, std::string& port, std::string& configDir) { int iport; try { po::options_description desc("Program Usage", 1024, 512); desc.add_options() ("help", "produce help message") ("host,h", po::value<std::string>(&host), "set the host server") ("port,p", po::value<int>(&iport), "set the server port") ("config,c", po::value<std::string>(&configDir), "set the config path") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); if (vm.count("help")) { std::cout << desc << "\n"; return false; } // There must be an easy way to handle the relationship between the // option "help" and "host"-"port"-"config" if (vm.count("host")) { std::cout << "host: " << vm["host"].as<std::string>() << "\n"; } else { std::cout << "\"host\" is required!" << "\n"; return false; } if (vm.count("port")) { std::cout << "port: " << vm["port"].as<int>() << "\n"; } else { std::cout << "\"port\" is required!" << "\n"; return false; } if (vm.count("config")) { std::cout << "config: " << vm["config"].as<std::string>() << "\n"; } else { std::cout << "\"config\" is required!" << "\n"; return false; } } catch(std::exception& e) { std::cerr << "Error: " << e.what() << "\n"; return false; } catch(...) { std::cerr << "Unknown error!" << "\n"; return false; } std::stringstream ss; ss << iport; port = ss.str(); return true; } int main(int argc, char** argv) { std::string host; std::string port; std::string configDir; bool result = process_command_line(argc, argv, host, port, configDir); if (!result) return 1; // Do the main routine here } 

我自己也遇到过这个问题。 解决scheme的关键是,函数po::store填充variables_mappo::notify引发遇到的任何错误,所以可以在发送任何通知之前使用vm

因此,按照Tim的说法 ,根据需要将每个选项设置为required,但在处理help选项后运行po::notify(vm) 。 这样它会退出,没有任何exception抛出。 现在,如果选项设置为required,缺less选项将导致required_optionexception被抛出,并使用get_option_name方法将错误代码减less到相对简单的catch块。

另外需要注意的是,你的选项variables是通过po::value< -type- >( &var_name )机制直接设置的,所以你不必通过vm["opt_name"].as< -type- >()来访问它们vm["opt_name"].as< -type- >()

这是完整的程序,按照rcollyer和蒂姆,他们的信用:

 #include <boost/program_options.hpp> #include <iostream> #include <sstream> namespace po = boost::program_options; bool process_command_line(int argc, char** argv, std::string& host, std::string& port, std::string& configDir) { int iport; try { po::options_description desc("Program Usage", 1024, 512); desc.add_options() ("help", "produce help message") ("host,h", po::value<std::string>(&host)->required(), "set the host server") ("port,p", po::value<int>(&iport)->required(), "set the server port") ("config,c", po::value<std::string>(&configDir)->required(), "set the config path") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); if (vm.count("help")) { std::cout << desc << "\n"; return false; } // There must be an easy way to handle the relationship between the // option "help" and "host"-"port"-"config" // Yes, the magic is putting the po::notify after "help" option check po::notify(vm); } catch(std::exception& e) { std::cerr << "Error: " << e.what() << "\n"; return false; } catch(...) { std::cerr << "Unknown error!" << "\n"; return false; } std::stringstream ss; ss << iport; port = ss.str(); return true; } int main(int argc, char** argv) { std::string host; std::string port; std::string configDir; bool result = process_command_line(argc, argv, host, port, configDir); if (!result) return 1; // else std::cout << "host:\t" << host << "\n"; std::cout << "port:\t" << port << "\n"; std::cout << "config:\t" << configDir << "\n"; // Do the main routine here } /* Sample output: C:\Documents and Settings\plee\My Documents\Visual Studio 2010\Projects\VCLearning\Debug>boost.exe --help Program Usage: --help produce help message -h [ --host ] arg set the host server -p [ --port ] arg set the server port -c [ --config ] arg set the config path C:\Documents and Settings\plee\My Documents\Visual Studio 2010\Projects\VCLearning\Debug>boost.exe Error: missing required option config C:\Documents and Settings\plee\My Documents\Visual Studio 2010\Projects\VCLearning\Debug>boost.exe --host localhost Error: missing required option config C:\Documents and Settings\plee\My Documents\Visual Studio 2010\Projects\VCLearning\Debug>boost.exe --config . Error: missing required option host C:\Documents and Settings\plee\My Documents\Visual Studio 2010\Projects\VCLearning\Debug>boost.exe --config . --help Program Usage: --help produce help message -h [ --host ] arg set the host server -p [ --port ] arg set the server port -c [ --config ] arg set the config path C:\Documents and Settings\plee\My Documents\Visual Studio 2010\Projects\VCLearning\Debug>boost.exe --host 127.0.0.1 --port 31528 --config . host: 127.0.0.1 port: 31528 config: . C:\Documents and Settings\plee\My Documents\Visual Studio 2010\Projects\VCLearning\Debug>boost.exe -h 127.0.0.1 -p 31528 -c . host: 127.0.0.1 port: 31528 config: . */ 

您可以指定一个选项是否足够容易[ 1 ],例如:

 ..., value<string>()->required(), ... 

但据我所知,没有办法代表不同的选项之间的关系program_options库。

一种可能性是用不同的选项集多次parsing命令行,如果你已经检查过“帮助”,你可以再次用另外三个选项进行parsing。 不过,我不确定我会不会考虑改进你的产品。

  std::string conn_mngr_id; std::string conn_mngr_channel; int32_t priority; int32_t timeout; boost::program_options::options_description p_opts_desc("Program options"); boost::program_options::variables_map p_opts_vm; try { p_opts_desc.add_options() ("help,h", "produce help message") ("id,i", boost::program_options::value<std::string>(&conn_mngr_id)->required(), "Id used to connect to ConnectionManager") ("channel,c", boost::program_options::value<std::string>(&conn_mngr_channel)->required(), "Channel to attach with ConnectionManager") ("priority,p", boost::program_options::value<int>(&priority)->default_value(1), "Channel to attach with ConnectionManager") ("timeout,t", boost::program_options::value<int>(&timeout)->default_value(15000), "Channel to attach with ConnectionManager") ; boost::program_options::store(boost::program_options::parse_command_line(argc, argv, p_opts_desc), p_opts_vm); boost::program_options::notify(p_opts_vm); if (p_opts_vm.count("help")) { std::cout << p_opts_desc << std::endl; return 1; } } catch (const boost::program_options::required_option & e) { if (p_opts_vm.count("help")) { std::cout << p_opts_desc << std::endl; return 1; } else { throw e; } }