我正在尝试编写一个命令行界面(CLI),使用boost::program_options
对现有代码进行扩展。该代码库利用了大量的boost::optional
参数,因此我希望能够从命令行中解析boost::optional
。如果没有指定,结果是boost::none
,如果指定,则获得初始化值。
当我尝试使用自定义的Boost验证器时,我遇到了bad_any_cast
的问题。以下是出现问题的最小完整可复现示例(MCVE)。
我有一个类
class MyClass {
public:
int x;
MyClass(const int a) : x(a) {};
};
还有一个针对该类的自定义Boost验证器。这种验证器的风格直接来自于Boost文档。
void validate(boost::any& v, const std::vector<std::string>& values,
MyClass* target_type, int) {
v = boost::any(boost::optional<MyClass>(boost::in_place(1)));
}
最后,我的主要功能是创建一个简单的解析器。
#include <boost/program_options.hpp>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/utility/in_place_factory.hpp>
int main(int argc, char** argv) {
po::options_description desc("");
desc.add_options()
("MyClass", po::value<boost::optional<MyClass>>()->default_value(boost::none, ""), "MyClass");
po::variables_map args;
po::store(po::parse_command_line(argc, argv, desc), args);
}
如果我在命令行上没有传递--MyClass
选项,代码可以成功运行。然而,如果我传递了--MyClass
选项,就会出现bad_any_cast
错误。
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_any_cast> >'
what(): boost::bad_any_cast: failed conversion using boost::any_cast
我用GDB逐步调试,在MyClass
的any_cast
中抛出了这个异常,但是如果在boost::program_options
之外编写类似的代码,它会成功运行。
例如,下面的代码将相同的boost::optional
强制转换为boost::any
,然后再次强制转换,可以成功运行且没有错误。
#include <iostream>
#include <boost/program_options.hpp>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
#include <boost/utility/in_place_factory.hpp>
namespace po = boost::program_options;
class MyClass {
public:
int x;
MyClass(const int a) : x(a) {};
};
int f(boost::any& v) {
v = boost::any(boost::optional<MyClass>(boost::in_place(1)));
}
int main(int argc, char** argv) {
boost::any v;
f(v);
boost::any_cast<boost::optional<MyClass>>(v);
}
我知道
program_options
支持default_value
,所以我可以在解析后使用if语句将基本值包装在可选项中,但我认为使用上面的自定义验证器方法会更清晰。是否有人对如何解决此问题有任何想法或建议?
boost::none
更改为boost::optional<MyClass>()
吗?boost::none
和boost::optional<MyClass>()
不是相同的类型,因此会导致任何转换失败。 - Alan Birtlesboost::none
实际上与boost::optional<T>
兼容,并表示可选项不包含值(即boost::optional<T> v.reset() == boost::none
将计算为 true)。此外,当将any_cast
应用于boost::none
时,代码可以正常工作,但是当将其应用于除boost::none
之外的任何内容时,则无法正常工作。感谢您的建议! - hyperdelia