I'm using Boost Program Options Library to parse the command line arguments.
I have the following requirements:
How I can deal with this? Here is the my code handling this, and I found it's very redundant, and I think there must be an easy to do, right?
#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 }
Program Options, part of the collection of Boost C++ Libraries, allows for definition and acquisition of (name, value) pairs from the user via conventional methods such as command line and config file. It is roughly analogous to getopt_long, but for use with C++.
Boost C++ Libraries Class template optional is a wrapper for representing 'optional' (or 'nullable') objects who may not (yet) contain a valid value. Optional objects offer full value semantics; they are good for passing by value and usage inside STL containers.
Some boost libraries are header-only, some are not, and for various reasons etc.
I've run into this issue myself. The key to a solution is that the function po::store
populates the variables_map
while po::notify
raises any errors encountered, so vm
can be used prior to any notifications being sent.
So, as per Tim, set each option to required, as desired, but run po::notify(vm)
after you've dealt with the help option. This way it will exit without any exceptions thrown. Now, with the options set to required, a missing option will cause a required_option
exception to be thrown and using its get_option_name
method you can reduce your error code to a relatively simple catch
block.
As an additional note, your option variables are set directly via the po::value< -type- >( &var_name )
mechanism, so you don't have to access them through vm["opt_name"].as< -type- >()
.
A code example is provided in Peters answer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With