【问题标题】:What is boost::program_options::notify() for?boost::program_options::notify() 有什么用?
【发布时间】:2011-10-30 20:08:24
【问题描述】:

这个问题是关于 C++ Boost program_options 库的。

所有教程都非常清楚,我应该在我完成的变量映射上调用notify(),但我不确定这实际上对我做了什么。注释掉似乎没有任何效果,文档也没有详细说明:

http://www.boost.org/doc/libs/1_47_0/doc/html/boost/program_options/notify.html

其他消息来源表明它运行“用户定义”功能。如果是这样,这些函数是如何注册的,它们是做什么的?他们会抛出异常吗?

【问题讨论】:

    标签: c++ boost


    【解决方案1】:

    notify() 是一个member function of value_semantic。它是一个钩子,一旦确定了选项的最终值,该选项应该采取的任何操作都可以自动完成并封装在它自己的函数中。这可以防止代码具有一个作用于每个选项的长函数。随着可能选项的增加,这种程序代码可能会变得笨拙。

    你可以看到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")
        ;
    

    这些声明指定第一个选项的默认值为 10、认为第二个选项可以出现多次和所有实例 应该合并,并且解析完成后,库将 调用函数 &your_function,传递“email”选项的值 作为论据。

    【讨论】:

    • 哦,我现在明白了。您必须寻找“通知者”,而不是通知。 notify 函数已经通过了对 value 的 const 引用,所以不能改变它吗?如果选项“不好”,除了抛出异常之外,我看不出你能做什么。
    • @olooney:目的是您采取该选项的任何预期操作。例如,如果您有一个更改搜索路径的选项,您的通知函数将修改搜索路径。正如我在回答中指出的那样,您可以在选项解析代码中执行相同的逻辑,方法是分别检查每个选项然后采取一些措施,但这可能会导致难以阅读或修改的长程序 blob。
    • 当然,但是没有能力改变 variable_map,将不透明的句柄传递给环境对象,或者绑定到仿函数(比如使用 boost::function),你真的受限于异常和全局 副作用。这对于更改工作目录或设置全局“详细”标志仍然有用,但它还不足以将大部分选项解析移动到通知程序中。也许我应该在做出判断之前尝试一下,我只是在这里进行理论分析。
    • 我在这里链接到 boost 源:stackoverflow.com/a/66865258/4561887。除了您的答案之外,查看源代码对我有帮助。
    【解决方案2】:

    当你提到“函子”时,我认为你是在正确的轨道上......

    通过将参数传递给某个对象的方法来处理选项是很常见的。如果您可以将方法包装到 notifier() 将接受作为参数的东西中,则可以使用通知器更直接地完成此操作。你可以。 (如果 boost::function 有这样做的方法,我对它还不够熟悉(现在懒得去研究它了)——下面使用来自 STDLIB 的 header 函数中的例程。)

    例子:

    您的选项之一是 --config-file,采用字符串参数,它告诉非默认配置文件的路径。您有一个名为 ConfigParser 的类。如果没有通知程序,您的代码可能如下所示:

    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
        ;
    

    【讨论】:

      【解决方案3】:

      我喜欢直奔源头。所以,给你: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_mapm 的所有notify() 函数,它是std::map&lt;std::string, variable_value&gt; 的包装器,并包含从命令选项(如std::strings)到variable_value 的映射s(任何类型)。

      现在this answer by @Conspicuous Compiler 有更多上下文,所以去阅读吧。除了源代码之外,查看他的答案对我有帮助。

      另外(正如 OP 已经知道的,但这是给其他人的),这里有一个 关于如何使用 &lt;boost/program_options.hpp&gt; 模块的介绍性 Boost 教程:https://www.boost.org/doc/libs/1_75_0/doc/html/program_options/tutorial.html. 这真的有点“挥手。”他们不希望您知道这些特定功能的真正作用。他们只想让你知道如何遵循模式和使用库,正如他们暗示的那样:

      接下来,对storeparse_command_linenotify 函数的调用导致vm 包含在命令行中找到的所有选项。

      (参考下面示例中的这段代码):

      po::store(po::parse_command_line(ac, av, desc), vm);
      po::notify(vm); 
      

      当您调用 add_options() 函数时,他们正在 C++ 中做一些非常漂亮的黑色魔法 vudu。

      这是他们的基本教程示例的完整上下文:

      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;
      }
      

      【讨论】:

        猜你喜欢
        • 2011-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-20
        • 1970-01-01
        • 2019-01-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多