【问题标题】:Handle no value option in Config file in Boost program_options在 Boost program_options 的 Config 文件中处理 no value 选项
【发布时间】:2020-08-27 07:51:28
【问题描述】:

这个问题之前已经在这里问过 - Boost parse_config_file, empty key value。但由于那里没有提供适当的解决方案,我再次提出这个问题,希望有人能提供更好的解决方案。

与上述问题不同,在我的情况下,代码不会引发 Boost 错误:

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() 同时添加选项,但它们都不起作用。

【问题讨论】:

  • 展示示例代码和配置不会有什么坏处。现在,人们必须从头开始。
  • @sehe 问题的链接提供了代码和配置示例。

标签: c++ boost boost-program-options


【解决方案1】:

更新 最初的答案有错误的想法。这是更新。

因此,您希望 foo=(没有值)表现得好像该行甚至不在配置中一样。

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

您可以通过发明自己的值语义(可以说是 mybool_switch)和/或解决value<my_particulat_bool> 来解决它,您可以在其中添加流操作,以便选项按照您想要的方式运行。换句话说,就是用大炮打苍蝇。

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

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

Live On Coliru

#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 << "\n---\n" << std::quoted(contents) << "\n";

        // 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 << "\n";
                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)\n";
            else
                std::cout << " value:" << entry.as<bool>() << "\n";
        }
    }
}

哪个会打印

---
""
 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

【讨论】:

  • Gah,再次阅读您的问题让我想知道这是否真的是您的问题(如果您是明确的,它会有所帮助)。也许你在追求这个:coliru.stacked-crooked.com/a/4ccb762029649112
  • 如果那是不是的话,那么毫无疑问,你需要在通知之前操作parsed_options中间。界面上Here's a good primer
  • 成功了 Live On Coliru。让我知道这是否是答案,我可以更新文本以反映它。请务必阅读之前链接的答案,了解此解决方案的基本原理。
  • 在存储它们之前迭代解析的选项似乎是一个非常好的解决方案。非常感谢 :)。只是想确认使用 bool_switch()、default_value() 和implicit_value() 与解决方案无关。
  • 是的。我对这些事情的看法是涵盖所有选项,因为问题没有具体说明,而且要获得确切的目标已经很棘手。很高兴有帮助。更新(替换)答案。
猜你喜欢
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
  • 2020-08-29
  • 2019-05-01
  • 2020-03-14
  • 2011-12-29
相关资源
最近更新 更多