Using boost::program_options
, I need to set the default_value
for having that default visible in the help message. However, it is still needed to know if the default was applied or if an argument was provided. (The logic will, in certain cases override an existing configuration if the argument pas provided).
Possible solutions:
Remove default values: but then the help message will not show the default.
Find a way to check if an argument was provided (How?)
Create the option_description
twice (one with defaults, another without). Not ideal.
int main( int argc, char* argv[])
{
namespace po = boost::program_options;
namespace fs = boost::filesystem;
std::string ip;
std::string port;
const std::string ip_arg = "ip";
const std::string port_arg = "ip";
po::options_description options("Options");
options.add_options()
(ip_arg, po::value<std::string>(&ip, "IP")->default_value("127.0.0.1")
(port_arg, po::value<std::string>(&port, "Port")->default_value("80"))
;
po::variables_map vm;
try
{
using bs = po::command_line_style::style_t;
boost::program_options::store(
boost::program_options::command_line_parser(argc, argv)
.options(options)
.style(bs::long_allow_next | bs::allow_long | bs::allow_short | bs::allow_dash_for_short |
bs::long_allow_adjacent | bs::short_allow_adjacent | bs::short_allow_next | bs::allow_long_disguise)
.run(),
vm);
po::notify(vm);
}
catch( ...)
{
std::cerr << "Some error" << std::endl;
return 1;
}
std::stringstream ss;
ss << options;
std::cout << ss.str() << std::endl; // Print help, visible defaults
if (vm.count(port_arg))
{
// Argument was provided, so make something
}
else
{
// Argument was no provided, make something else.
}
return 0;
}
How can I detect if an argument was provided, or if the default was applied?
Your options descriptions are broken. Let's fix them. I opted against the ip_arg
/port_arg
variables (note how you had them copy pasted wrong anyways).
po::options_description options("Options");
options.add_options()
("ip", po::value<std::string>(&ip)->default_value("127.0.0.1"), "IP") //
("port", po::value<std::string>(&port)->default_value("80"), "Port")
;
Now you can be sure that port
is always set, so .count()
or .contains()
are redundant. Instead, ask the map entry whether it has been defaulted:
if (vm["port"].defaulted()) {
std::cout << "Port defaulted (" << port << ")\n";
} else {
std::cout << "Port specified as " << port << "\n";
}
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <iostream>
namespace po = boost::program_options;
namespace fs = boost::filesystem;
int main( int argc, char* argv[])
{
std::string ip;
std::string port;
po::options_description options("Options");
options.add_options()
("ip", po::value<std::string>(&ip)->default_value("127.0.0.1"), "IP") //
("port", po::value<std::string>(&port)->default_value("80"), "Port")
;
po::variables_map vm;
try {
using bs = po::command_line_style::style_t;
boost::program_options::store(
boost::program_options::command_line_parser(argc, argv)
.options(options)
.style(bs::long_allow_next | bs::allow_long | bs::allow_short |
bs::allow_dash_for_short | bs::long_allow_adjacent |
bs::short_allow_adjacent | bs::short_allow_next |
bs::allow_long_disguise)
.run(),
vm);
po::notify(vm);
} catch (...) {
std::cerr << "Some error" << std::endl;
return 1;
}
std::cout << options << std::endl;
if (vm["port"].defaulted()) {
std::cout << "Port defaulted (" << port << ")\n";
} else {
std::cout << "Port specified as " << port << "\n";
}
}
Prints e.g.
$ ./test --ip=192.168.1.2
Options:
--ip arg (=127.0.0.1) IP
--port arg (=80) Port
Port defaulted (80)
or
$ ./test --port=8080
Options:
--ip arg (=127.0.0.1) IP
--port arg (=80) Port
Port specified as 8080