I have an application that loads options in two steps. In the second step, some options may be undeclared in the options_description
object (depending on what options were passed in the first step).
There seems to be no option to ignore undeclared, similar to the ones that exist for parsing command line arguments and configuration files.
A minimal working example:
#include <boost/program_options.hpp>
namespace po = boost::program_options;
int main() {
int opt1;
po::options_description options("my app options");
options.add_options()
("opt1", po::value<int>(&opt1)->default_value(0), "option 1");
po::variables_map env;
po::store(po::parse_environment(options, "MYAPP_"), env);
po::notify(env);
printf("opt1: %d\n", opt1);
return 0;
}
By default you'll get a value of zero, as expected:
$ ./a.out
opt1: 0
If you set MYAPP_OPT1
, it also works as expected
$ MYAPP_OPT1=123 ./a.out
opt1: 123
However, if you set a variable that is not specified in the configuration file, it will crash.
$ MYAPP_UNDEFINED=456 ./a.out
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::program_options::unknown_option> >'
what(): unrecognised option
Aborted (core dumped)
There's also another annoying thing -- if instead of declaring "opt1"
I declare "OPT1"
, it won't even recognize MYAPP_OPT1
!
IMHO this would be a nice addition to the boost library, making it on-par with the command-line and configuration-file parsers.
The following is adapted from my gist.
When using Boost's program_options to load environment variables, there is no way of telling boost to ignore those that were not specified in the options_description
object.
This snippet shows how to get similar behavior to the allow_unregistered()
option available to command line and configuration file parsers.
For example, if you try to read MYAPP_ONE
by specifying an option called one
and using prefix MYAPP
in parse_environment
, it will work just fine.
The issue arises if there is another MYAPP_X
that wasn't included in the options_description
object. Then an exception will be thrown.
If you use the program arguments (argc
, argv
) or a configuration file, there is an option in the library to simply ignore the options that weren't declared in the options_description
.
For environment variables, that is not the case. This snippet will simply read the options you declared and will ignore any others that may have been declared.
Thus, behaving like the allow_unregistered()
functionality.
po::options_description options("My Options");
lib_options.add_options()
(
"MY_VAR",
po::value<bool>(&my_var)->default_value(false),
"Dummy boolean test"
)
;
po::variables_map env;
po::store(po::parse_environment(
options,
[options](const std::string& var) {
return std::any_of(
options.options().cbegin(),
options.options().cend(),
[var](auto opt) { return var == opt->long_name(); }) ? var : "";
}), env);
po::notify(env);