Search code examples
c++file-ioboost-program-options

How do I use a boost::program_options notifier with multiple options?


I'm writing a physics simulation that reads in a whole bunch of system parameters with the boost::program_options library and I'd like to "automatically" set some parameters that arise as combinations of the user-input values. For example, if I have

[parameters]
    c0 = 299792458
    dt = 0.004

as the speed of light and timestep in my input file, I'd like to set a value cdt = c0*dt in the same structure I'm using to store c0 and dt after both options get read. Notifiers, as I understand, are a way to process an input option with a function, but I haven't seen a way to do the same thing with multiple options -- what's the best way to go about doing this?


Solution

  • I do not see any direct option how to achieve this using boost program_options. Notifiers are being called after only one option is parsed. However you can combine several workarounds to achieve acceptable solution - store values in separate structure, let program_options to fill all computed values (directly or using setter function) after parsing is complete.

    My simplified suggestion:

    #include <boost/program_options.hpp>
    #include <iostream>
    
    using namespace boost::program_options;
    
    struct SimulationConfig {
      int c0;
      float dt;
      float cdt;
    
      void setCdt() {
        cdt = c0*dt;
      }
    };
    
    int main(int argc, const char *argv[])
    {
    
      SimulationConfig config;
      try
      {
        options_description desc{"Options"};
        desc.add_options()
          ("help,h", "Help screen")
          ("c0", value<int>(&config.c0), "Speed of light")
          ("dt", value<float>(&config.dt), "Time interval");
    
        variables_map vm;
        store(parse_command_line(argc, argv, desc), vm);
        notify(vm);
    
    
        if (vm.count("help"))
          std::cout << desc << '\n';
        else if (vm.count("c0") && vm.count("dt")) {
          //config.cdt = vm["c0"].as<int>() * vm["dt"].as<float>();
          config.setCdt();
          std::cout << "Cdt is set to: " << config.cdt << std::endl;
        }
    
      }
      catch (const error &ex)
      {
        std::cerr << ex.what() << '\n';
      }
    }