【问题标题】:How to determine if an argment was provided to boost::program_options, or if the default is used instead?如何确定是否为 boost::program_options 提供了参数,或者是否使用默认值?
【发布时间】:2025-11-22 13:55:02
【问题描述】:

使用boost::program_options,我需要设置default_value 以使该默认值在帮助消息中可见。但是,仍然需要知道是否应用了默认值或是否提供了参数。 (在某些情况下,如果提供了参数,该逻辑将覆盖现有配置)。

可能的解决方案:

  • 删除默认值:但是帮助消息不会显示默认值。

  • 找到一种方法来检查是否提供了参数(如何?)

  • 两次创建option_description(一个有默认值,另一个没有)。不理想。

    int main( int argc, char* argv[])
    {
        namespace po = boost::program_options;
        namespace fs = boost::filesystem;
    
        std::string ip;
        std::string port;
    
        const std::string ip_arg = "ip";
        const std::string port_arg = "ip";
    
        po::options_description options("Options");
        options.add_options()
        (ip_arg, po::value<std::string>(&ip, "IP")->default_value("127.0.0.1")
        (port_arg, po::value<std::string>(&port, "Port")->default_value("80"))
        ;
    
        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::stringstream ss;
        ss << options;
        std::cout << ss.str() << std::endl; // Print help, visible defaults
    
        if (vm.count(port_arg))
        {
            // Argument was provided, so make something
        }
        else
        {
            // Argument was no provided, make something else.
        }
    
        return 0;
    }
    

如何检测是否提供了参数,或者是否应用了默认值?

【问题讨论】:

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


    【解决方案1】:

    您的选项描述已损坏。让我们修复它们。我选择反对 ip_arg/port_arg 变量(注意你是如何让它们复制粘贴错误的)。

    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")
     ;
    

    现在您可以确定port 始终被设置,因此.count().contains() 是多余的。相反,询问地图条目是否已默认:

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

    现场演示

    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";
        }
    }
    

    打印例如

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

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

    【讨论】:

    • countdefaulted 之间的差异让我抓狂。谢谢你的精彩解释和回答。
    • 这种混淆是可以理解的。你只是忘记了超越你期望它生活的地方。我想这是库的可用性问题,但与大多数 Boost 库一样,可用性在灵活性和通用性方面占据第二位。
    最近更新 更多