【问题标题】:Sane way to use boost::program_options with INI and command line?使用带有 INI 和命令行的 boost::program_options 的合理方法?
【发布时间】:2021-01-08 03:17:58
【问题描述】:

我想编写一个解析配置文件的程序,并允许命令行覆盖那里写的内容。所以我可以有一个配置文件,上面写着:

[section1]
opt1=42

[section2]
opt2=17

然后,我可以使用以下命令运行命令:

./so --opt2=3

程序会得到opt1 为42 和opt2 和3。我使用下面的程序来尝试这样做:

#include <fstream>
#include <boost/program_options.hpp>

namespace po = boost::program_options;

int main(int argc, char *argv[]) {
    po::options_description options1("section1");
    options1.add_options()
            ("opt1", po::value<int>(), "Option 1");

    po::options_description options2("section2");
    options2.add_options()
            ("opt2", po::value<int>(), "Option 2");

    po::options_description options;
    options.add(options1);
    options.add(options2);

    po::variables_map values;
    po::store( po::command_line_parser( argc, argv ).options(options).run(), values );

    std::ifstream iniFile( "options.ini" );

    po::store(
            parse_config_file( iniFile, options ),
            values );
}

这当然行不通。 Boost::program_options 想要将section1 下的opt1 称为section1.opt1。但是,如果我这样做,我的程序会在两个方面变得更难维护:

  • 我需要定义两个options_descriptions,一个用于INI,一个用于命令行。
  • 由于选项的键现在不同,我需要手动合并两者。

有没有办法在不手动工作的情况下实现这一点?

【问题讨论】:

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


    【解决方案1】:

    简单的解决方案是不使用这些部分。选项描述中的“部分”与 ini 文件中的部分可能存在一些混淆。

    ini 文件中的部分引用以嵌入句点命名的选项:"section1.opt1"。所以你可以简单地把配置文件写成:

    opt1=42
    
    # perhaps with a comment
    opt2=17
    

    Live On Coliru

    #include <boost/program_options.hpp>
    #include <fstream>
    #include <iostream>
    
    namespace po = boost::program_options;
    
    int main(int argc, char* argv[]) {
        po::options_description options;
        options.add_options()
            ("opt1", po::value<int>(), "Option 1")
            ("section2.opt2", po::value<int>(), "Option 2");
    
        std::cout << options << "\n";
    
        po::variables_map values;
        po::store(po::parse_command_line(argc, argv, options), values);
    
        std::ifstream iniFile("options.ini");
    
        po::store(parse_config_file(iniFile, options), values);
    
        auto report = [&values](char const* name) {
            if (auto opt = values[name]; !opt.empty())
                std::cout << name << ": " << opt.as<int>() << "\n";
        };
    
        report("opt1");
        report("opt2");
        report("section1.opt1");
        report("section2.opt2");
    }
    

    打印

    echo "opt1=42" >> options.ini; ./a.out --section2.opt2 99
      --opt1 arg            Option 1
      --section2.opt2 arg   Option 2
    
    opt1: 42
    section2.opt2: 99
    

    【讨论】:

    • 如果您仍然需要这些部分,您可以像我在hereherehere 那样做一些后期处理
    • 答案完全忽略了这个问题。一个回答说“你不能那样做”会有点帮助。您的回答基本上是说“获取部分的解决方案是不使用部分”。您的答案字面意思是对问题中信息的重复。
    • 好的。这是一个苛刻的阅读,但我很欣赏这个解释。
    • 我将问题更多地解析为“这没有达到我的预期/希望”,这就是为什么我放大了可能的混淆来源(描述部分不是“部分”)。由于您的问题仅集中在更改 /one side/ (描述)上,因此我选择了另一种方式(更改配置文件),这确实满足了所有规定的要求。我承认在my comment 中改变可能不是你的意图。
    • 我猜结果是,根据您自己的评价,答案是“有点帮助”。我通过Stack Overflow 礼节提交了这通常不值得否决。很抱歉我在回答的措辞中造成了任何混乱(沟通很困难)。干杯。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多