luk*_*k32 2 c++ boost boost-program-options
我偶然发现了标题中定义的问题.我有一个应用程序,它创建一个options_description
然后使用add_options()
它的实例.与示例非常相似:
options_description desc;
desc.add_options()
("help", "produce help")
("optimization", value<int>()->default_value(10), "optimization level")
;
Run Code Online (Sandbox Code Playgroud)
我的问题是,如何修改optimization
此调用之后的默认值.这甚至可能吗?文档对我来说似乎很模糊.根据我的理解,这个问题可以推广到任何值语义,就像value_semantic
括号中的第二个参数一样.
动机
我觉得这可能是不可能的.所以我想表达我对这种功能的动力.也许我的意图设计是有缺陷的,所以你可以提出别的建议.
我有几个程序执行非常相似的任务,并分享相当多的参数和开关.我以为我可以将公共参数重构为单独的基类.我虽然可以以类似的方式重构命令行解析.boost::program_options
我的想法做得很好.我将options_description
实例构造为基类中的私有属性,并在那里添加常用选项.然后在初始化的派生类中,我add_options()
再次在此对象上执行添加更多特定选项.这看起来很整洁,我的工作速度非常快.
然后我注意到所有派生类都有一个共同的选项,但它有一个不同的默认值真的很好.即输出文件的名称.对于app1是app1.out,app2 - app2.out等
当然我可以将输出文件名选项移动到add_options
派生类中,但它看起来很愚蠢和冗余,因为即使在语义上,除默认值外,一切都是相同的.另一种解决方法是从基类中的默认值和派生类的后解析步骤中退出,检查选项是否已设置并手动应用(默认)值.然而,这似乎也是多余的,因为预期的功能似乎在库本身中实现.
我将尝试提供一个代码示例,以便您可以在以后或请求时更好地感受它.虽然,我认为我的方法很清楚.
编辑 - 代码示例 它是在Rob的回答之后写的,所以我试图保持在命名约定内.
Base - 执行解析并允许将优化级别设置为整数:
#include <boost/program_options.hpp>
namespace po = boost::program_options;
class BaseClass {
public:
BaseClass::BaseClass();
virtual int parse(const int argc, char** argv);
private:
po::options_description m_desc;
po::variables_map vm;
int optimization_level;
};
BaseClass::BaseClass():
m_desc()
{
m_desc.add_options()
("help", "produce help")
("optimization", value<int>()->default_value(10), "optimization level")
;
}
int BaseClass::parse(const int argc, char** argv)
{
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if (vm.count("help")) { std::cout << desc << "\n"; return 1; }
optimization_level = vm["optimization"].as<int>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
高度优化的版本,允许选择执行花哨的东西:
class HighlyOptimizedClass : public BaseClass {
public:
HighlyOptimizedClass();
virtual int parse(const int argc, char** argv);
private:
bool fancy_optimizations;
};
HighlyOptimizedClass(): BaseClass() {
m_desc.add_options()
("fancy,f", po::value<bool>()->zero_tokens(), "perform fancy optimizations")
;
}
HighlyOptimizedClass::parse(const int argc, char** argv)
{
int ret = BaseClass::parse(argc, argv); //execute base function
if( ret ) return ret; //return if it didnt succed
if ( vm.count("fancy") ) fancy_optimizations = 1; // non-base stuff
return 0;
}
Run Code Online (Sandbox Code Playgroud)
非优化版本,允许打开详细调试:
class NonOptimizedClass : public BaseClass {
public:
NonOptimizedClass();
virtual int parse(const int argc, char** argv);
private:
bool verbose_debug;
};
NonOptimizedClass(): BaseClass() {
m_desc.add_options()
("verbose,v", po::value<bool>()->zero_tokens(), "genrates TONS of output")
;
}
NonOptimizedClass::parse(const int argc, char** argv)
{
int ret = BaseClass::parse(argc, argv); // execute base function
if( ret ) return ret; // return if it didnt succed
if ( vm.count("verbose") ) verbose_debug = 1; // non-base stuff
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我试图垂直压缩它,但它反正很长= /.对不起,如果我太过分了.反过来,这些例子清晰而自成一体.
该BaseClass
套了几乎一切,并解析常见的东西.派生类在构造函数和重载解析中添加自己的选项.他们会执行基本解析器并检查错误.这也使得--help
工作.
现在的问题是修改每个派生的优化的默认值.因为将它设置得非常低NonOptimizedClass
并且非常高,这将是很好的OptimizedClass
.
您可以调用options_description::find("optimization", ...)
以获取对关联的引用option_description
,并且其semantic
方法将为您提供指向value_semantic
您最初在调用时提供的指针add_options
.但是,它是一个const指针,所以看起来你不允许修改它所指向的内容.
但是,value_semantic
当您创建它时,它不是const,这意味着使用它const_cast
来删除option_description
适用的const限定条件应该是安全的.您还必须将value_semantic
对象类型转换回typed_value
您最初调用时所获得的正确类型value<T>
.
option_description const& optimization = desc.find("optimization", false);
shared_ptr<const value_semantic> cvalue = optimization.semantic();
shared_ptr<value_semantic> value = const_pointer_cast<value_semantic>(cvalue);
shared_ptr<typed_value<int>> tvalue = dynamic_pointer_cast<typed_value<int>>(value);
assert(tvalue);
tvalue->default_value(20);
Run Code Online (Sandbox Code Playgroud)
另一种设计,它避免了在定义选项后必须修改它们(显然不是program_options
设计用来做的事情),是让程序特定的派生类将所需的默认值传递给基类.然后,基类可以在定义优化选项时使用该值.
BaseClass::BaseClass(int default_optimization):
m_desc()
{
m_desc.add_options()
("help",
"produce help")
("optimization",
value<int>()->default_value(default_optimization),
"optimization level")
;
}
HighlyOptimizedClass::HighlyOptimizedClass():
BaseClass(99)
{ }
NonOptimizedClass::NonOptimizedClass():
BaseClass(0)
{ }
Run Code Online (Sandbox Code Playgroud)