对于枚举类型

时间:2016-10-28 12:30:01

标签: c++ boost-program-options

我有一个程序接受一组可以用来选择某些行为的互斥标志。假设标志为--csv--xml--json,分别选择CSV,XML和JSON作为输出格式。也可以通过使用单个--format标记来完成,然后像--format=csv--format=xml--format=json一样使用,效果相同,但我不能也不会想要更改命令行界面。

我已经找到了一种方法来检查最多使用其中一个选项,即它们的共同排他性。我对此的解决方案并不是最漂亮的,但我对此部分没问题。

退出此检查,我的程序目前看起来像这样。

#include <iostream>
#include <boost/program_options.hpp>

namespace po = boost::program_options;

enum output_formats {format_default, format_csv, format_xml, format_json};

int
main(int argc, char * * argv)
{
  auto options = po::options_description{"Options"};
  options.add_options()
    ("csv", "produce output in CSV format")
    ("xml", "produce output in XML format")
    ("json", "produce output in JSON format");
  auto vm = po::variables_map{};
  po::store(po::parse_command_line(argc, argv, options), vm);
  po::notify(vm);
  // Check that at most one of the options was passed (not shown here).
  auto format = format_default;
  if      (vm.count("csv"))  format = format_csv;
  else if (vm.count("xml"))  format = format_xml;
  else if (vm.count("json")) format = format_json;
  std::clog << "Output format: " << format << "\n";
}

它正在运行,但我不喜欢ifelse if级联来确定用户传递的选项(如果有的话)。

我已经看到boost::program_options::bool_switch允许我定义将设置bool的标志,并且它可以正常工作。我想实现enum_switch所以我可以将相同的技术应用到我的enum并重新编写代码。

int
main(int argc, char * * argv)
{
  auto format = format_default;
  auto options = po::options_description{"Options"};
  options.add_options()
    ("csv", enum_switch(&format, format_csv), "produce output in CSV format")
    ("xml", enum_switch(&format, format_xml), "produce output in XML format")
    ("json", enum_switch(&format, format_json), "produce output in JSON format");
  auto vm = po::variables_map{};
  po::store(po::parse_command_line(argc, argv, options), vm);
  po::notify(vm);
  std::clog << "Output format: " << format << "\n";
}

我在Boost中找到了bool_switch的实现,它看起来像这样。

BOOST_PROGRAM_OPTIONS_DECL typed_value<bool>*
bool_switch(bool* v)
{
    typed_value<bool>* r = new typed_value<bool>(v);
    r->default_value(0);
    r->zero_tokens();
    return r;
}

因此,我已经像这样实施了enum_switch

template <typename T>
boost::program_options::typed_value<T> *
enum_switch(T * dest, const T value)
{
  auto tv = new boost::program_options::typed_value<T>{dest};
  tv->default_value(value);
  tv->zero_tokens();
  return tv;
}

我注意到的第一件事是Boost抱怨我的enum没有定义>>运算符。好吧,我定义了一个,事实证明它永远不会被调用。不幸的是,代码仍然没有按预期工作。如果我在没有选项的情况下调用我的程序,format将为format_json,如果我通过--xml,则会收到以下错误:

option '--xml' requires at least one argument

如果我通过--xml 1我仍然会收到相同的错误,如果我使用--xml=1,那么我会收到这个有趣的错误:

option '--xml' does not take any arguments

使用我的enum显然适用于bool的内容,我错过了什么?

1 个答案:

答案 0 :(得分:1)

尽管这个问题已经存在多年了,但我发现它是因为我也遇到了同样的问题。

长话短说:代替default_vaue(),您需要在implicit_value()实例上调用typed_value来设置所需的格式值。

我也在Program_options代码中进行了一些深入研究,以更好地了解此解决方案。来自implicit_value()的api-doc:

  

指定一个隐式值,如果给出该选项,则将使用它,但不带   一个相邻的值。使用此选项意味着显式值是可选的。

如果给定一个隐式值,并且没有其他显式参数,则在调用variables_map期间,该调用设置的值将直接存储到po::store()中。否则,将调用validate()来检查给定的参数,然后再存储它们。一般的验证函数总是希望至少有1个参数,而zero_tokens()已经将最大值设置为0。

对于bool_switch()增强,已经提供了一个重载的validate(),它以适当的方式处理这种隐式情况(除默认值0外,仅其他1个值)。