【问题标题】:Split value for vector<string> option in boost program_optionsboost program_options 中vector<string> 选项的拆分值
【发布时间】:2020-08-29 20:51:54
【问题描述】:

我正在开发一个通过配置文件读取一些选项的应用程序。该代码使用 boost program_options 库来读取选项。

应用程序代码有一个类,它执行以下与读取选项值相关的任务-

1)function1() - 定义所有可能的有效选项。将它们添加到 option_description 对象。
2)function2() - 解析配置文件并填充 variable_map 对象。
3)function3() - 返回选项的值。此函数如下所示 -

template<typename T>
T function3(string optName){
    try{return vm[optName].as<T>();}
    catch(exception& e){ //some error handling message}
}

现在有一个选项-

vector_of_string_option=value1,value2,value3

为此,我将此选项添加到选项描述对象中-

("vector_of_string_option", po::value<vector<string>>(), "vector string");

为此,vm["vector_of_string_option"].as&lt;vector&lt;string&gt;&gt;() 返回一个带有第一个元素的向量 - "value1,value2,value3"

我希望返回的值是一个包含 3 个值的向量 - {"value1" , "value2" , "value3"}。

由于 function3() 是类中的模板化函数,我无法为向量编写专门的函数(例如,使用 boost::split 拆分字符串)。

如果有办法,我会为矢量使用相同的方法。

那么,有没有办法通过 program_options 固有地实现这一点?或任何其他建议在我的代码中实现这一点?

【问题讨论】:

  • 回答后,我不知道你为什么要对function1function2function3进行如此详细的介绍,你可以只显示代码,似乎只有function3是相关的。

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


【解决方案1】:

您使用 Boost Program Options 的想法是使用多令牌/组合选项。

我们一起来

1)function1() - 定义所有可能的有效选项。添加 他们到一个option_description 对象。

auto function1() {
    po::options_description desc;
    for (auto opt : s_opts)
        desc.add_options()(opt, po::value<std::string>());
    desc.add_options()
        ("vector_of_string_option", po::value<VoS>()->multitoken()->composing(), "vector string")
        ;
    return desc;
}

到目前为止一切顺利

2)function2() - 解析 配置文件并填充variable_map 对象。

auto function2(std::istream&& is) {
    auto d = function1();
    po::parsed_options parsed = po::parse_config_file(is, d, false);
    po::variables_map vm;
    po::store(parsed, vm);
    po::notify(vm);

    return vm;
}

仍然没有问题。

3)function3()-

返回一个选项的值。这个函数看起来像这样-

template <typename T>
T function3(std::string optName, po::variables_map const& vm) {
    try {
        return vm[optName].as<T>();
    } catch (std::exception const& e) {
        std::cerr << "Whoops: " << e.what() << "\n";
        exit(1);
    }
}

好的。

int main() {
    auto vm = function2(std::istringstream(R"(
bar=BARRRR
# bar=QUXXXX # "cannot be specified more than once"
vector_of_string_option=value1
vector_of_string_option=value2
vector_of_string_option=value3
)"));
    std::cout << function3<std::string>("bar", vm) << "\n";
    for (auto& v : function3<VoS>("vector_of_string_option", vm)) {
        std::cout << " - " << std::quoted(v) << "\n";
    }
}

打印:

BARRRR
 - "value1"
 - "value2"
 - "value3"

我希望返回的值是一个包含 3 个值的向量 - {"value1" , "value2" , "value3"}。

已经完成,请看Live On Coliru

由于 function3() 是类中的模板化函数,我无法为向量编写专门的函数(例如,使用 boost::split 拆分字符串)。

当然可以!你不能/部分/专攻,但你可以专攻:

template <>
VoS function3<VoS>(std::string optName, po::variables_map const& vm) {
    try {
        VoS result;
        auto const& raw = vm[optName].as<VoS>();

        using namespace boost::algorithm;
        for(auto& rv : raw) {
            VoS tmp;
            split(tmp, rv, is_any_of(",; "), token_compress_on);
            result.insert(result.end(), tmp.begin(), tmp.end());
        }
        return result;
    } catch (std::exception const& e) {
        std::cerr << "Whoops: " << e.what() << "\n";
        exit(1);
    }
}

这使得您可以使用多个值,但也可以拆分每个值:

int main() {
    auto vm = function2(std::istringstream(R"(
bar=BARRRR
# bar=QUXXXX # "cannot be specified more than once"
vector_of_string_option=value1, value2, value3
vector_of_string_option=value4, value5, value6
)"));
    std::cout << function3<std::string>("bar", vm) << "\n";
    for (auto& v : function3<VoS>("vector_of_string_option", vm)) {
        std::cout << " - " << std::quoted(v) << "\n";
    }
}

打印

BARRRR
 - "value1"
 - "value2"
 - "value3"
 - "value4"
 - "value5"
 - "value6"

再看一遍Live On Coliru

红利

如果你想要部分特化,要么将function3 的实现委托给模板类,要么使用标签调度。这也使得解析成set&lt;int&gt;list&lt;bool&gt; 成为可能/容易。

草稿:http://coliru.stacked-crooked.com/a/7971dd671010d38e

【讨论】:

  • 感谢您的回复。但是,您错过了这些函数是在一个类中定义的(我在开头提到过)。因此,在您对 function3 的实现中将不起作用。 variables_map 对象也是该类的私有成员。
  • 为什么不呢?那是无关紧要的。而且,如果你认为它是相关的,那只是强调你需要展示代码。
  • (这是“Bonus Take”中的想法草稿:coliru.stacked-crooked.com/a/7971dd671010d38e
  • 这是对答案代码的修改,以包含类和私有字段等:Live On Coliru 我没有看到问题 - 它实际上更容易,因为现在您可以只重载function3,而不必专门化 [GotW #49, Sutters Mill]()gotw.ca/publications/mill17.htm
  • 谢谢。此外,对于 vector 选项,即使未使用 multtoken(),我也可以在配置文件中多次指定它。对于其他类型,当我在配置文件中多次指定它时,会发生异常。有没有办法对 VoS 选项做同样的事情?现在,我通过检查 function3() 中向量的 size() 来做到这一点,如果它大于 1,我会引发错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-29
  • 2011-02-25
  • 2012-08-27
  • 2016-02-22
相关资源
最近更新 更多