This question is about the C++ Boost program_options library.
All the tutorials are very clear that I should call notify()
on my completed variable map, but I'm not sure what this is actually doing for me. Commenting it out didn't seem to have any effect, and the documentation didn't go into much detail:
http://www.boost.org/doc/libs/1_47_0/doc/html/boost/program_options/notify.html
Other sources suggest that it runs "user-defined" functions. If so, how are those functions registered and what do they do? Might they throw exception开发者_开发知识库s?
notify()
is a member function of value_semantic. It is a hook that is provided so that, once the final value of an option is determined, any action that should be taken with that option can be done automatically and be encapsulated in its own function. This prevents code from having one long function that acts on each of the options. As the possible options grow, that kind of procedural code can get unwieldy.
You can see an example of setting a notify function in the Boost manual:
options_description desc;
desc.add_options()
("compression", value<int>()->default_value(10), "compression level")
("email", value< vector<string> >()
->composing()->notifier(&your_function), "email")
;
These declarations specify that default value of the first option is 10, that the second option can appear several times and all instances should be merged, and that after parsing is done, the library will call function &your_function, passing the value of the "email" option as argument.
I think you are on the right track when you mention "functor"...
It's quite common for an option to be processed by passing its argument(s) to some object's method. This can be done more directly with notifiers if you can wrap the method into something that notifier() will accept as an argument. And you can. (If boost::function has a way of doing so, I'm not familiar enough with it (and am too lazy to go study up on it now) -- the following uses the routines in header functional from STDLIB.)
Example:
One of your options is --config-file, taking a string argument, which tells the path of a non-default configuration file. You have a class called ConfigParser. Without notifiers, your code might look something like this:
ConfigParser *cp = new ConfigParser();
std::string cp_path;
desc.add_options()
("config-file", value<std::string>(&cp_path)->default_value("~/.myconfig"), "Config File")
// ... the rest of your options
;
cp->setPath(cp_path);
With notifiers:
#include <functional>
ConfigParser *cp = new ConfigParser();
desc.add_options()
("config-file", value<std::string>()->default_value("~/.myconfig")->notifier(std::bind1st(std::mem_fun(&ConfigParser::setPath), cp)), "Config File")
// ... the rest of your options
;
I like to look straight to the source. So, here you go: https://github.com/boostorg/program_options/blob/develop/include/boost/program_options/variables_map.hpp#L52:
/** Runs all 'notify' function for options in 'm'. */
BOOST_PROGRAM_OPTIONS_DECL void notify(variables_map& m);
So, it runs all the notify()
functions for the variables_map
, m
, which is a wrapper around std::map<std::string, variable_value>
, and contains a map from command options (as std::string
s) to variable_value
s (any type).
Now this answer by @Conspicuous Compiler has more context, so go read it. Looking at his answer in addition to the source code helps me.
Also (as the OP already knows, but this is for other people), here is an introductory Boost tutorial on how to use the <boost/program_options.hpp>
module: https://www.boost.org/doc/libs/1_75_0/doc/html/program_options/tutorial.html. It's really kind of "hand-wavy." They don't expect you to have a clue what these particular functions really do. All they want you to know is how to follow the pattern and use the library, as they insinuate when they say:
Next, the calls to
store
,parse_command_line
andnotify
functions causevm
to contain all the options found on the command line.
(referring to this code from the example below):
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm);
They are doing some pretty fancy black-magic vudu in C++ as it is when you call the add_options()
function.
Here is the full context of their basic tutorial example:
example/first.cpp:
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
/* The simplest usage of the library.
*/
#include <boost/program_options.hpp>
namespace po = boost::program_options;
#include <iostream>
#include <iterator>
using namespace std;
int main(int ac, char* av[])
{
try {
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
("compression", po::value<double>(), "set compression level")
;
po::variables_map vm;
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm);
if (vm.count("help")) {
cout << desc << "\n";
return 0;
}
if (vm.count("compression")) {
cout << "Compression level was set to "
<< vm["compression"].as<double>() << ".\n";
} else {
cout << "Compression level was not set.\n";
}
}
catch(exception& e) {
cerr << "error: " << e.what() << "\n";
return 1;
}
catch(...) {
cerr << "Exception of unknown type!\n";
}
return 0;
}
They have more examples here: https://github.com/boostorg/program_options/tree/develop/example.
精彩评论