Boost program_options store multiple config file parse results into one parsed_options

冷暖自知 提交于 2021-01-28 21:25:57

问题


I'm trying to parse unregistered options in any number of files provided at command line. Let's say I have files:

configs0.ini
configs1.ini
configs2.ini

And I wanted to support any number of these.

My code (simplified):

namespace po = boost::program_options;
po::options_description cmd_opts{"Options"};
po::options_description config_file_opts;
po::variables_map vm;

cmd_opts.add_options()                                                                                                                                                                                                     
   ("help,h", "Help message")                                       
   ("config_files", po::value<std::vector<std::string>>()->multitoken(), "Configuration files to get settings from")

po::parser.options(reg_config_file_opts).allow_unregistered();

po::store(parse_command_line(argc, argv, cmd_opts), vm);

config_files = vm["config_files"].as<std::vector<std::string>>();
po::parsed_options parsed_opts;

for(auto file : config_files) {
   std::ifstream ifs(file, std::ifstream::in);                                                                                                                                                                             
   if(ifs.fail()) {
      std::cerr << "Error opening config file: " << file << std::endl;
      return false;
   }
   ifs.close();

   <NEED HELP HERE>
   parsed_opt.add(parse_config_file(ifs, reg_config_file_opts));
}

po::store(parsed_opts, vm);

Does parsed_options have some sort of .add ability?


回答1:


The library distinguishes three layers:

  • the description component
  • the parsers component
  • the storage component

The design assumes that you will be using one or more sets of descriptions with one or more parsers, and combine the results into one storage.

In practice this means you will store into the same variable map, and notify to update any value-semantics with side-effects.

Live Demo

  • File main.cpp

    #include <boost/program_options.hpp>
    #include <boost/program_options/cmdline.hpp>
    #include <boost/program_options/config.hpp>
    #include <fmt/format.h>
    #include <fmt/ranges.h>
    #include <fstream>
    
    namespace po = boost::program_options;
    
    int main() {
        for (auto args : {
                std::vector{"test.exe"},
                std::vector{"test.exe", "--config_files", "a.cfg", "b.cfg", "c.cfg"},
            })
        {
            int const argc    = args.size();
            char const** argv = args.data();
    
            po::options_description cmd_opts{"Options"};
    
            using values = std::vector<std::string>;
            cmd_opts.add_options()                                                                                                                                                                                                     
                ("help,h", "Help message")                                       
                ("config_files", po::value<values>()->multitoken(), "Configuration files to get settings from")
                ;
    
            po::variables_map vm;
            po::variables_map cfg_vm; // can also reuse vm
            po::store(parse_command_line(argc, argv, cmd_opts), vm);
    
            auto& config_files = vm["config_files"];
            if (!config_files.empty()) {
    
                po::options_description config_file_opts;
                config_file_opts.add_options()                                                                                                                                                                                                     
                    ("foo", po::value<values>()->composing())
                    ("bar_a", po::value<values>()->composing())
                    ("bar_b", po::value<values>()->composing())
                    ("bar_c", po::value<values>()->composing())
                    ;
    
                for(auto file : config_files.as<values>()) try {
                    std::ifstream ifs(file);
                    po::store(parse_config_file(ifs, config_file_opts), cfg_vm);
                } catch(std::exception const& e) {
                    fmt::print(stderr, "{}: {}\n", file, e.what());
                }
    
                fmt::print("Cmdline opts\n");
                for (auto& [k, v] : vm) {
                    fmt::print("{}={}\n", k, v.as<values>());
                }
                fmt::print("Combined configs\n");
                for (auto& [k, v] : cfg_vm) {
                    fmt::print("{}={}\n", k, v.as<values>());
                }
            }
        }
    }
    
  • File a.cfg

    foo=foo_val_a
    bar_a=bar_val_a
    
  • File b.cfg

    foo=foo_val_b
    bar_b=bar_val_b
    
  • File c.cfg

    foo=foo_val_c
    bar_c=bar_val_c
    

Prints:

Cmdline opts
config_files={"a.cfg", "b.cfg", "c.cfg"}
Combined configs
bar_a={"bar_val_a"}
bar_b={"bar_val_b"}
bar_c={"bar_val_c"}
foo={"foo_val_a", "foo_val_b", "foo_val_c"}


来源:https://stackoverflow.com/questions/62399047/boost-program-options-store-multiple-config-file-parse-results-into-one-parsed-o

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!