17
//Using boost program options to read command line and config file data
    #include <boost/program_options.hpp>
    using namespace std;
    using namespace boost;
    namespace po = boost::program_options;

int main (int argc, char *argv[])
{
    po::options_description config("Configuration");
    config.add_options()
                ("IPAddress,i","IP Address")
                ("Port,p","Port")
                 ;

    po::variables_map vm;
    po::store(po::parse_command_line(argc, argv, config),vm);
    po::notify(vm);

    cout << "Values\n";

    string address = (vm["IPAddress"].as<std::string >()).c_str();
    string port = (vm["Port"].as<std::string>()).c_str();

    cout << (vm["IPAddress"].as< string >()).c_str();
    cout << " " << (vm["Port"].as<string>()).c_str();

    return 0;

}

输入的值是否无法打印?

这是gdb输出,似乎是演员问题:

在抛出 'boost::exception_detail::clone_impl 的实例后调用终止

' what(): boost::bad_any_cast: 使用 boost::any_cast 转换失败

        Program received signal SIGABRT, Aborted.
        0x0000003afd835935 in raise () from /lib64/libc.so.6
string address = (vm["IPAddress"].as<std::string >()).c_str();

是错误发生的地方;我尝试过 std::string 和 string 的结果相同。

testboostpo -i 192.168.1.10 -p 5000

是命令行。

我尝试声明类型,如下所示:

config.add_options()
        ("IPAddress,i", po::value<std::string>(), "IP Address")
            ("Port,p", po::value<std::string>(), "Port");

但错误仍然发生。

这可能是一个真正的错误吗?

4

5 回答 5

17

您会看到从boost::bad_any_cast抛出的异常,po::variables_map因为 的两个const char*参数重载po::options_description_easy_init::operator()未指定po::value_semantic类型,因此将其转换为 astd::string将不起作用。如果要将值转换为 a std::string,并且您的应用程序需要它,请使用required()值语义。

#include <boost/program_options.hpp>
namespace po = boost::program_options;

int main (int argc, char *argv[])
{
    po::options_description config("Configuration");
    config.add_options()
                ("IPAddress,i", po::value<std::string>()->required(), "IP Address")
                ("Port,p", po::value<std::string>()->required(), "Port")
                ;

    try {
        po::variables_map vm;
        po::store(po::parse_command_line(argc, argv, config),vm);
        po::notify(vm);
        std::cout << "Values" << std::endl;

        const std::string address = vm["IPAddress"].as<std::string>();
        const std::string port = vm["Port"].as<std::string>();

        std::cout << "address: " << address << std::endl;
        std::cout << "port: " << port << std::endl;
    } catch ( const std::exception& e ) {
        std::cerr << e.what() << std::endl;
        return 1;
    }

    return 0;
}

请注意添加的 catch 块,因为解析可以(并且正如您所注意到的)会抛出异常。这是一个示例会话:

samm$ ./a.out
the option '--IPAddress' is required but missing
samm$ ./a.out --IPAddress 127.0.0.1
the option '--Port' is required but missing
samm$ ./a.out --IPAddress 127.0.0.1 --Port 5000
Values
address: 127.0.0.1
port: 5000
samm$ 

这是一个在线演示,显示了相同的行为,由 COMpile 链接运行 (coliru) 提供。

于 2013-03-20T21:59:28.993 回答
4

添加选项时,您需要将 ip-address 和 port 声明为字符串:

config.add_options()
    ("IPAddress,i", po::value<std::string>(), "IP Address")
    ("Port,p", po::value<std::string>(), "Port")
    ;
于 2013-03-20T21:48:54.537 回答
2

如果您没有正确处理可选参数,也会出现同样的消息。

Sam 的解决方案指出了必需的参数,并且 OP 的代码建议必需 - 只需将它们标记为必需。对于可选输入,Boost PO 教程为我们提供了一个模板,用于在转换之前检查选项是否存在:

if(vm.count("address")) 
{
    const std::string address = vm["IPAddress"].as<std::string>();
    std::cout << "address: " << address << std::endl;
}
if(vm.count("port")) 
    const std::string port = vm["Port"].as<std::string>();
    std::cout << "port: " << port << std::endl;
}

我的问题 - 我复制/粘贴并忘记将 if 测试与使用情况对齐!

于 2016-04-11T00:27:46.397 回答
1

我收到了类似的错误消息,但这是因为我使用的是简写i,而不是IPAddress.

// this throws the cast exception
const std::string address = vm["i"].as<std::string>();
// this does not
const std::string address = vm["IPAddress"].as<std::string>();

Boost 采用第一个声明的。所以如果你的选项被声明为IPAddress,i你需要使用vm["IPAddres"],而i,IPAddress你需要使用vm["i"]

于 2021-01-21T22:39:00.403 回答
0

不一定和这个人有同样的问题,但这里有一些让我印象深刻的事情:

如果你把你的类型放在匿名命名空间中,将会有两个类同名但实例不同,并且转换将失败。例如:

a.hpp:

namespace {
class MyClass {...};
}

b.cpp:

#include "a.hpp"
cli_options.add_options()("test", po::value<MyClass>(), "test desc");

c.cpp:

#include "a.hpp" // THIS WILL MAKE A DIFFERENT "MyClass"
vm["test"].as<MyClass>();  // Fails at runtime.

它失败了,因为MyClassinb.cpp和 one inc.cpp不是同一个类。因为匿名命名空间。

删除匿名命名空间解决了这个问题。

于 2018-03-11T15:15:26.193 回答