Boost程序选项遍历variables_map

时间:2014-01-08 23:36:39

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

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;

4 个答案:

答案 0 :(得分:13)

提升variable_map使用boost::any作为值,以便您可以尝试使用boost::any_cast<T>来查找类型。 也许是这样的

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

答案 1 :(得分:3)

boost::program_options::variable_map本质上是std::map<std::string, boost::any>,这意味着它使用类型擦除来存储值。由于原始类型丢失,因此无法在不将其强制转换为正确类型的情况下提取它。您可以实现第二个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,其中包含一些组合类型,但它足够接近您的用例,您应该能够应用类似的东西。

答案 2 :(得分:0)

我没有专门研究过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
}

答案 3 :(得分:0)

我认为比迭代参数更好的方法是使用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;
}