c++boostboost-program-options

How to determine if an argment was provided to boost::program_options, or if the default is used instead?


Using boost::program_options, I need to set the default_value for having that default visible in the help message. However, it is still needed to know if the default was applied or if an argument was provided. (The logic will, in certain cases override an existing configuration if the argument pas provided).

Possible solutions:


How can I detect if an argument was provided, or if the default was applied?


Solution

  • Your options descriptions are broken. Let's fix them. I opted against the ip_arg/port_arg variables (note how you had them copy pasted wrong anyways).

    po::options_description options("Options");
    options.add_options()
        ("ip", po::value<std::string>(&ip)->default_value("127.0.0.1"), "IP") //
        ("port", po::value<std::string>(&port)->default_value("80"), "Port")
     ;
    

    Now you can be sure that port is always set, so .count() or .contains() are redundant. Instead, ask the map entry whether it has been defaulted:

    if (vm["port"].defaulted()) {
        std::cout << "Port defaulted (" << port << ")\n";
    } else {
        std::cout << "Port specified as " << port << "\n";
    }
    

    Live Demo

    Live On Coliru

    #include <boost/filesystem.hpp>
    #include <boost/program_options.hpp>
    #include <iostream>
    namespace po = boost::program_options;
    namespace fs = boost::filesystem;
    
    int main( int argc, char* argv[])
    {
        std::string ip;
        std::string port;
    
        po::options_description options("Options");
        options.add_options()
            ("ip", po::value<std::string>(&ip)->default_value("127.0.0.1"), "IP") //
            ("port", po::value<std::string>(&port)->default_value("80"), "Port")
         ;
    
        po::variables_map vm;
        try {
            using bs = po::command_line_style::style_t;
    
            boost::program_options::store(
                boost::program_options::command_line_parser(argc, argv)
                    .options(options)
                    .style(bs::long_allow_next | bs::allow_long | bs::allow_short |
                           bs::allow_dash_for_short | bs::long_allow_adjacent |
                           bs::short_allow_adjacent | bs::short_allow_next |
                           bs::allow_long_disguise)
                    .run(),
                vm);
    
            po::notify(vm);
        } catch (...) {
            std::cerr << "Some error" << std::endl;
            return 1;
        }
    
        std::cout << options << std::endl;
    
        if (vm["port"].defaulted()) {
            std::cout << "Port defaulted (" << port << ")\n";
        } else {
            std::cout << "Port specified as " << port << "\n";
        }
    }
    

    Prints e.g.

    $ ./test --ip=192.168.1.2
    Options:
      --ip arg (=127.0.0.1) IP
      --port arg (=80)      Port
    
    Port defaulted (80)
    

    or

    $ ./test --port=8080
    Options:
      --ip arg (=127.0.0.1) IP
      --port arg (=80)      Port
    
    Port specified as 8080