boost::program_options 自定义验证和默认值
boost::program_options custom validate and default value
我正在使用 boost::program_options 来解析参数。因为我不能破坏兼容性,所以我需要允许多次指定一些参数。例如,我需要对字符串(最后一个获胜)或布尔值(每次出现都会切换值)执行此操作。
让我们展示一下我在 bool 上的内容(对于字符串应该更容易,因为使用参数时默认值是什么并不重要,因为它会被新值覆盖)。我有自己的 class BoolValue 和自定义验证函数,它会在每次出现时切换值。因此,如果您有值为 false 的变量并像这样调用程序
./program -t -t -t
它再次将其切换为 true、false 和 true。
我可以用下面的代码实现它,如果默认值为 false,它工作正常。但有时我需要默认值为 true(因此上面的示例会将其切换为 false,true,最后再次为 false)。
我当然可以制作两个 class,例如 TrueValue 和 FalseValue,但它看起来不太好。那么 - 我能否以某种方式读取指定的 default_value 内部验证函数以在仍然为空时进行初始赋值?
// my custom class
class BoolOption {
public:
BoolOption(bool initialState = false) : state(initialState) {}
bool getState() const {return state;}
void switchState() {state = !state;}
private:
bool state;
};
// two test variables
BoolOption test1;
BoolOption test2;
// validate
void validate(boost::any &v, std::vector<std::string> const &xs, BoolOption*, long)
{
if (v.empty()) {
v = BoolOption(true); // here is the problem
// it works when default false only (of course)
// I don't know how to read the default_value here
} else {
boost::any_cast<BoolOption&>(v).switchState();
}
}
optionsDescription->add_options()
("test1,t", po::value<BoolOption>(&test1)->default_value(BoolOption(true), "true")->zero_tokens(), "")
("test2,T", po::value<BoolOption>(&test2)->default_value(BoolOption(false), "false")->zero_tokens(), "")
;
// output result
cout << test1.getState() << endl;
cout << test2.getState() << endl;
如上所述,非常尴尬的解决方案是为此目的设置两个 classes,也可以使用模板来完成,例如
template <bool B> class SwitchOption {
public:
SwitchOption() : value(B) {}
bool getValue() const {return value;}
void setValue(bool value) {this->value = value;}
void switchState() {value = !value;}
string toStr() {return value ? "true" : "false";}
private:
bool value;
};
// so validate as
template <bool B> void validate(boost::any &v, vector<string> const &xs __unused, SwitchOption<B>*, long)
{
if (v.empty()) {
v = SwitchOption<B>();
}
boost::any_cast<SwitchOption<B>&>(v).switchState();
}
// and add_options like this:
("switch,s", boost::program_options::value<SwitchOption<true> >(&variableName)->default_value(SwitchOption<true>(), "true")->zero_tokens(), "")
// can be done with macro, but still I have to specify "true" here in add_options and also when defying the variable itself as
// SwitchOption<true> variableName;
// which is bad duplication
迷失在过于复杂的解决方案中:-)
在没有默认值(始终为 false)的情况下按原样使用,并在为那些默认值为 true 的变量完成选项解析后切换。
我正在使用 boost::program_options 来解析参数。因为我不能破坏兼容性,所以我需要允许多次指定一些参数。例如,我需要对字符串(最后一个获胜)或布尔值(每次出现都会切换值)执行此操作。
让我们展示一下我在 bool 上的内容(对于字符串应该更容易,因为使用参数时默认值是什么并不重要,因为它会被新值覆盖)。我有自己的 class BoolValue 和自定义验证函数,它会在每次出现时切换值。因此,如果您有值为 false 的变量并像这样调用程序
./program -t -t -t
它再次将其切换为 true、false 和 true。
我可以用下面的代码实现它,如果默认值为 false,它工作正常。但有时我需要默认值为 true(因此上面的示例会将其切换为 false,true,最后再次为 false)。
我当然可以制作两个 class,例如 TrueValue 和 FalseValue,但它看起来不太好。那么 - 我能否以某种方式读取指定的 default_value 内部验证函数以在仍然为空时进行初始赋值?
// my custom class
class BoolOption {
public:
BoolOption(bool initialState = false) : state(initialState) {}
bool getState() const {return state;}
void switchState() {state = !state;}
private:
bool state;
};
// two test variables
BoolOption test1;
BoolOption test2;
// validate
void validate(boost::any &v, std::vector<std::string> const &xs, BoolOption*, long)
{
if (v.empty()) {
v = BoolOption(true); // here is the problem
// it works when default false only (of course)
// I don't know how to read the default_value here
} else {
boost::any_cast<BoolOption&>(v).switchState();
}
}
optionsDescription->add_options()
("test1,t", po::value<BoolOption>(&test1)->default_value(BoolOption(true), "true")->zero_tokens(), "")
("test2,T", po::value<BoolOption>(&test2)->default_value(BoolOption(false), "false")->zero_tokens(), "")
;
// output result
cout << test1.getState() << endl;
cout << test2.getState() << endl;
如上所述,非常尴尬的解决方案是为此目的设置两个 classes,也可以使用模板来完成,例如
template <bool B> class SwitchOption {
public:
SwitchOption() : value(B) {}
bool getValue() const {return value;}
void setValue(bool value) {this->value = value;}
void switchState() {value = !value;}
string toStr() {return value ? "true" : "false";}
private:
bool value;
};
// so validate as
template <bool B> void validate(boost::any &v, vector<string> const &xs __unused, SwitchOption<B>*, long)
{
if (v.empty()) {
v = SwitchOption<B>();
}
boost::any_cast<SwitchOption<B>&>(v).switchState();
}
// and add_options like this:
("switch,s", boost::program_options::value<SwitchOption<true> >(&variableName)->default_value(SwitchOption<true>(), "true")->zero_tokens(), "")
// can be done with macro, but still I have to specify "true" here in add_options and also when defying the variable itself as
// SwitchOption<true> variableName;
// which is bad duplication
迷失在过于复杂的解决方案中:-)
在没有默认值(始终为 false)的情况下按原样使用,并在为那些默认值为 true 的变量完成选项解析后切换。