我有一个程序接受一组可以用来选择某些行为的互斥标志。假设标志为--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";
}
它正在运行,但我不喜欢if
,else 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
的内容,我错过了什么?
答案 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个值)。