所有的教程都很清楚,我应该在完成变量映射后调用
notify()
,但我不确定这对我有什么作用。注释掉它似乎没有任何影响,并且文档没有详细介绍:
http://www.boost.org/doc/libs/1_47_0/doc/html/boost/program_options/notify.html
其他来源表明它运行“用户定义”的函数。如果是这样,这些函数如何注册,它们做什么?它们可能会抛出异常吗?notify()
,但我不确定这对我有什么作用。注释掉它似乎没有任何影响,并且文档没有详细介绍:
http://www.boost.org/doc/libs/1_47_0/doc/html/boost/program_options/notify.html
其他来源表明它运行“用户定义”的函数。如果是这样,这些函数如何注册,它们做什么?它们可能会抛出异常吗?notify()
是value_semantic的成员函数。它是一个钩子,提供了一种方式,使得一旦确定选项的最终值,就可以自动执行任何应该执行的操作,并将其封装在自己的函数中。这样可以防止代码拥有一个长函数,对每个选项进行操作。随着可能的选项增加,这种过程式代码可能会变得难以控制。
您可以在Boost手册中看到设置通知函数的示例:
options_description desc;
desc.add_options()
("compression", value<int>()->default_value(10), "compression level")
("email", value< vector<string> >()
->composing()->notifier(&your_function), "email")
;
当你提到“函数对象”时,我认为你走在了正确的轨道上...
一种常见的处理选项的方式是将其参数传递给某个对象的方法。如果您可以将该方法包装成一个notifier()接受的参数,则可以更直接地使用notifiers进行处理。而且您确实可以这样做。(如果boost::function有这样做的方法,我不太熟悉它(现在也太懒得去学习它) - 以下使用STDLIB中头文件functional中的例程。)
例如:
您的其中一个选项是--config-file,接受一个字符串参数,指定非默认配置文件的路径。您有一个名为ConfigParser的类。没有notifiers,您的代码可能如下所示:
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);
使用通知器:
#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
;
我喜欢直接查看源代码。所以,这里是链接: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);
因此,它会运行所有variables_map
的notify()
函数,m
是std::map<std::string,variable_value>
的包装器,并包含从命令选项(作为std::string
)到variable_value
的映射(任何类型)。
现在这个由@Conspicuous Compiler提供的答案有更多的上下文信息,所以请阅读它。查看他的答案以及源代码对我很有帮助。
此外(正如原帖作者已经知道的,但这是为其他人准备的),这里有一个关于如何使用<boost/program_options.hpp>
模块的入门Boost教程:https://www.boost.org/doc/libs/1_75_0/doc/html/program_options/tutorial.html.它真的有点“手摇”,他们并不指望你知道这些特定函数到底做了什么。他们想让你知道的只是如何遵循模式和使用库,就像他们在说:
接下来,对
store
、parse_command_line
和notify
函数的调用会导致vm
包含在命令行上找到的所有选项。
(参考下面示例中的代码):
po::store(po::parse_command_line(ac, av, desc), vm);
po::notify(vm);
当你调用add_options()
函数时,他们在C++中进行了一些相当高级的黑魔法。
这是他们基本教程示例的完整上下文:
// 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;
}
这里有更多的示例:https://github.com/boostorg/program_options/tree/develop/example。