【问题标题】:Equivalent to boost::program_options::bool_switch for enum types等效于枚举类型的 boost::program_options::bool_switch
【发布时间】:2017-03-11 08:24:48
【问题描述】:

我有一个程序,它接受一组互斥标志,可用于选择某些行为。假设标志是--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 没有定义 &gt;&gt; 运算符。好的,我定义了一个,结果它永远不会被调用。不幸的是,代码仍然无法按预期工作。如果我在没有选项的情况下调用我的程序,format 将是format_json,如果我通过了,比如--xml,我会收到以下错误:

option '--xml' requires at least one argument

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

option '--xml' does not take any arguments

我缺少什么来使用我的enum 显然适用于bool

【问题讨论】:

    标签: c++ boost-program-options


    【解决方案1】:

    尽管这个问题已经有好几年了,但我现在找到了它,因为我遇到了同样的问题。

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

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

    指定一个隐式值,如果给出选项,将使用该值,但没有 一个相邻的值。使用 this 意味着显式值是可选的。

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

    对于bool_switch(),boost 已经提供了一个重载的validate(),它以正确的方式处理这种隐式情况(除了默认值 0 之外只有 1 个其他值)。

    【讨论】:

      猜你喜欢
      • 2019-01-14
      • 1970-01-01
      • 1970-01-01
      • 2014-01-17
      • 1970-01-01
      • 2012-05-31
      • 1970-01-01
      • 2017-03-12
      • 1970-01-01
      相关资源
      最近更新 更多