![](/img/trans.png)
[英]boost:bad_any_cast: failed conversion using boost:any_cast error
[英]How to solve “boost::bad_any_cast: failed conversion using boost::any_cast” when using boost program options?
//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");
但错误仍然发生。
这可能是一个真正的错误吗?
您会看到从po::variables_map
抛出的boost::bad_any_cast
异常,因为po::options_description_easy_init::operator()
的两个const char*
参数重载未指定po::value_semantic
类型,因此将其转换为std::string
不起作用。 如果要将值转换为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$
这是一个在线演示,展示了相同的行为,由编译链接运行 (coliru) 提供。
添加选项时,您需要将 ip-address 和 port 声明为字符串:
config.add_options()
("IPAddress,i", po::value<std::string>(), "IP Address")
("Port,p", po::value<std::string>(), "Port")
;
如果您没有正确处理可选参数,也会出现相同的消息。
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 测试与用法对齐!
不一定与这个人遇到的问题相同,但这里有一些让我着迷的东西:
如果将类型放在匿名命名空间中,则会有两个具有相同名称但实例不同的类,并且转换将失败。 例如:
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.
它失败,因为MyClass
在b.cpp
和一个在c.cpp
是不一样的类。 因为匿名命名空间。
删除匿名命名空间可以解决问题。
我有一个类似的错误消息,但这是因为我使用的是速记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"]
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.