【问题标题】:Boost program options iterate over variables_mapBoost程序选项迭代variables_map
【发布时间】:2014-01-08 23:36:38
【问题描述】:
po::options_description desc("This are the options that are available");
    desc.add_options()("help", "print help")(
        "deer", po::value<uint32_t>(), "set how many deer you want")(
        "rating", po::value<uint32_t>(), "how good ?")(
        "name", po::value<std::string>(), "and your name is ... ?");

po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);

在代码的以下部分中,我尝试遍历 vm

for (const auto& it : vm) {
      std::cout << it.first.c_str() << " "
                << it.second.as<it.pair::second_type>() << "\n";
    }

这里的重点是vm 包含相同类型的keys,但是具有不同类型的值,在此示例中,我将uint32_tstd::string 混合在一起。

我如何迭代这种容器?我想避免使用冗长的方法,所以我试图只迭代这个数据结构。

编辑:

我忘记写了,但是很明显

namespace po = boost::program_options;

【问题讨论】:

    标签: c++ boost c++11 boost-program-options


    【解决方案1】:

    boost variable_map 使用boost::any 作为值,因此您可以尝试使用boost::any_cast&lt;T&gt; 来找出类型。 也许是这样的

    for (const auto& it : vm) {
      std::cout << it.first.c_str() << " ";
      auto& value = it.second.value();
      if (auto v = boost::any_cast<uint32_t>(&value))
        std::cout << *v;
      else if (auto v = boost::any_cast<std::string>(&value))
        std::cout << *v;
      else
        std::cout << "error";
    }
    

    【讨论】:

      【解决方案2】:

      boost::program_options::variable_map本质上是std::map&lt;std::string, boost::any&gt;,这意味着它使用类型擦除来存储值。因为原始类型丢失了,所以如果不将其转换为正确的类型,就无法提取它。您可以实现第二个map,其中包含选项名称作为键,提取函数作为值,允许您在运行时将值分派到适当的提取器。

      using extractor = std::map<std::string, void(*)(boost::variable_value const&)>;
      

      using extractor = std::map<std::string, 
                                 std::function<void(boost::variable_value const&)>;
      

      如果您的提取器更复杂并且不会转换为简单的函数指针。将打印uint32_t 的提取器示例是

      auto extract_uint32_t = [](boost::variable_value const& v) {
                                   std::cout << v.as<std::uint32_t>();
                              };
      

      那么您的循环将如下所示:

      for (const auto& it : vm) {
        std::cout << it.first.c_str() << " "
        extractor_obj[it.first](it.second) 
        std::cout << "\n";
      }
      

      这是一个live demo,其中包含一些组合类型,但它与您的用例足够接近,您应该能够应用类似的东西。

      【讨论】:

        【解决方案3】:

        我没有专门研究 boost::program_options 模板,但你可能会做一些通用的事情,比如使用模板函数,根据类型不同地解析命令:

        template <typename T>
        void HandleCommand( T command )
        {
            // Generic solution
        }
        
        template <>
        void HandleCommand( const po::value<std::string>& command )
        {
            // Do something with the string
        }
        
        template <>
        void HandleCommand( const po::value<uint32_t>& command )
        {
            // Do something with the unsigned int
        }
        

        【讨论】:

          【解决方案4】:

          我认为比迭代参数更好的方法是使用positional_options_description

          使用示例:

          po::positional_options_description p;
          desc.add_options()
          (...);
          p.add("opt1", 1);
          p.add("opt2", 1);
          p.add("opt3", 1);
          
          if (vm.size() != 3)
          {
              std::cerr << "Command must be have 3 parameters.\n";
              return 1;
          }
          

          【讨论】:

            猜你喜欢
            • 2012-08-27
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-12-13
            • 1970-01-01
            相关资源
            最近更新 更多