关于C#:在Boost program_options中的配置文件中处理无值选项

Handle no value option in Config file in Boost program_options

在此之前已经有人问过这个问题-Boost parse_config_file,空键值。但是,由于那里没有提供适当的解决方案,因此我再次提出要求,希望有人可以提供更好的解决方案。

与上述问题不同,就我而言,代码未引发Boost错误:

1
boost::program_options::invalid_option_value

相反,对于string options,它将值设置为empty string(""),对于bool,它将值设置为true。我的代码的目的是确定是否在配置文件中设置了某些选项。我希望使用vm[optionName].count()(其中vm是variables_map对象)对其进行测试,但是在未像option=这样指定值的情况下,此方法返回true,因此无法使用。
我还尝试了-在添加选项的同时vm[optionName].defaulted()vm[optionName].empty()implicit_value()default_value(),但是它们都不起作用。


UPDATE最初的答案有错误的主意。这是更新。

因此,您希望foo=(无值)的行为就像配置中没有该行一样。

这意味着默认值语义(即通知时发生的事情-将状态从解析器组件迁移到存储组件)不是很好。

您可以通过发明自己的价值语义(可以说是mybool_switch)和/或解决value<my_particulat_bool>的问题,在其中添加流操作,从而使该选项表现出您想要的方式来铺平道路。换句话说,使用佳能射击苍蝇。

但是,到目前为止,最简单的选择是在解析器阶段进行干预,在您notify()之前更改parsed_options

这是一个带有现场演示的相当完整的插图:

Coliru直播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <boost/program_options/config.hpp>
#include <boost/program_options.hpp>
#include <iostream>
#include <iomanip>

namespace po = boost::program_options;

int main() {
    po::options_description desc;
    desc.add_options()
        ("foo", po::bool_switch())
        ("bar", po::bool_switch()->default_value(false))
        ("qux", po::bool_switch()->implicit_value(false))
        ;

    std::set<std::string> const bool_switches {"foo","bar","qux" };

    for (std::string contents :
            {"","foo=","foo=true",
                 "bar=","bar=true",
                 "qux=","qux=true"})
    {
        std::istringstream iss(contents);
        po::parsed_options parsed = po::parse_config_file(iss, desc, false);

        std::cout <<"\
---\
"
<< std::quoted(contents) <<"\
"
;

        // the magic is here:
        for (auto it = parsed.options.begin(); it!= parsed.options.end();) {
            using V = std::vector<std::string>;
            V const& v = it->value;
            if (bool_switches.count(it->string_key) && (v==V{} || v==V{""})) {
                std::cout <<"*** Discarding config key without a value:" << it->string_key <<"\
"
;
                it = parsed.options.erase(it);
            } else {
                ++it;
            }
        }

        po::variables_map vm;
        po::store(parsed, vm);

        for (auto& key : bool_switches) {
            auto& entry = vm[key];
            std::cout <<"" << key <<" ->" << std::boolalpha
                << (entry.empty()?" .empty()":"")    
                << (entry.defaulted()?" .defaulted()":"");
            if (entry.empty())
                std::cout <<" (no value)\
"
;
            else
                std::cout <<" value:" << entry.as<bool>() <<"\
"
;
        }
    }
}

将打印哪个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
---
""
 bar -> .defaulted() value:false
 foo -> .defaulted() value:false
 qux -> .defaulted() value:false

---
"foo="
*** Discarding config key without a value: foo
 bar -> .defaulted() value:false
 foo -> .defaulted() value:false
 qux -> .defaulted() value:false

---
"foo=true"
 bar -> .defaulted() value:false
 foo -> value:true
 qux -> .defaulted() value:false

---
"bar="
*** Discarding config key without a value: bar
 bar -> .defaulted() value:false
 foo -> .defaulted() value:false
 qux -> .defaulted() value:false

---
"bar=true"
 bar -> value:true
 foo -> .defaulted() value:false
 qux -> .defaulted() value:false

---
"qux="
*** Discarding config key without a value: qux
 bar -> .defaulted() value:false
 foo -> .defaulted() value:false
 qux -> .defaulted() value:false

---
"qux=true"
 bar -> .defaulted() value:false
 foo -> .defaulted() value:false
 qux -> value:true