Ich verwende die Boost-Programmoptionsbibliothek, um die Befehlszeilenargumente zu analysieren.
Ich habe folgende Anforderungen:
- Sobald "Hilfe" bereitgestellt wird, sind alle anderen Optionen optional.
- Sobald "Hilfe" nicht bereitgestellt wird, sind alle anderen Optionen erforderlich.
Wie kann ich damit umgehen? Hier ist der Code, der damit umgeht, und ich fand, dass er sehr redundant ist, und ich denke, es muss einfach sein, oder?
#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
}
Hier ist das komplette Programm von rcollyer und Tim, an die die Credits gehen:
#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:\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:\Debug>boost.exe Error: missing required option config C:\Debug>boost.exe --host localhost Error: missing required option config C:\Debug>boost.exe --config . Error: missing required option host C:\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:\Debug>boost.exe --host 127.0.0.1 --port 31528 --config . host: 127.0.0.1 port: 31528 config: . C:\Debug>boost.exe -h 127.0.0.1 -p 31528 -c . host: 127.0.0.1 port: 31528 config: . */
quelle
boost::program_options::required_option
damit Sie das Fehlen einer erforderlichen Option direkt behandeln können, anstatt sie von fangen zu lassenstd::exception
.Sie können angeben, dass eine Option leicht genug erforderlich ist [ 1 ], z.
..., value<string>()->required(), ...
Soweit ich weiß, gibt es jedoch keine Möglichkeit, Beziehungen zwischen verschiedenen Optionen in der Bibliothek program_options darzustellen.
Eine Möglichkeit besteht darin, die Befehlszeile mehrmals mit verschiedenen Optionssätzen zu analysieren. Wenn Sie bereits nach "Hilfe" gesucht haben, können Sie die drei anderen Optionen nach Bedarf erneut analysieren. Ich bin mir nicht sicher, ob ich das für eine Verbesserung gegenüber dem halten würde, was Sie haben.
quelle
->required()
, aber dann kann der Benutzer die Hilfeinformationen nicht abrufen--help
(ohne alle anderen erforderlichen Optionen anzugeben), da andere Optionen erforderlich sind.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; } }
quelle