boost :: program_options自定义验证和默认值

时间:2018-08-08 08:24:10

标签: c++ boost command-line-arguments boost-program-options

我正在使用boost :: program_options解析参数。因为我不能破坏兼容性,所以我需要允许多次指定一些参数。我需要这样做,例如用于字符串(最后一个获胜)或布尔值(每次出现都会切换值)。

让我们展示一下我在bool上拥有的功能(对于字符串,它应该更容易使用,因为使用参数时默认的值并不重要,因为它会被新值覆盖)。我有自己的类BoolValue和自定义验证函数,该函数在每次发生时都会切换值。因此,如果您的变量值为false并像这样调用程序

./program -t -t -t

将其切换为true,false和true。

我可以使用以下代码实现它,并且如果默认值为false,它可以正常工作。但是有时候我需要默认值为true(因此,上面的示例会将其切换为false,true,最后再次变为false)。

我当然可以创建两个类,如TrueValue和FalseValue,但是看起来不太好。所以-在仍然为空时,我可以以某种方式读取validate函数中指定的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;

如上所述,非常尴尬的解决方案是为此目的有两个类,也可以使用模板来完成,例如

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

丢在太复杂的解决方案中:-)

1 个答案:

答案 0 :(得分:0)

按原样使用,没有默认值(始终为false),并在对默认值应为true的变量进行选项解析后切换。