std::any_cast 在将 void* 转换为函数指针时抛出错误 any_cast
std::any_cast throws a bad any_cast error when converting void* to function pointer
下面是我写的代码,
std::unordered_map<std::string_view, std::any> symbols_;
symbols_["foo"] = dlsym(handle_), "foo");
当我使用 any_cast
return (std::any_cast<void(*)()>(symbols_["foo"]))();
,程序会报错:bad any_cast.
我找到主要原因是因为函数.
template<typename _Tp>
void* __any_caster(const any* __any)
判断条件为false然后returnnullptr.
else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage
#if __cpp_rtti
|| __any->type() == typeid(_Tp)
#endif
){
any::_Arg __arg;
__any->_M_manager(any::_Op_access, __any, &__arg);
return __arg._M_obj;
}
return nullptr;
我想知道
1.why __any->_M_manager == &any::_Manager<_Up>::_S_manage
和 __any->type() == typeid(_Tp)
都是假的,
2.and我该如何解决这个问题(继续使用std::any)。
这是一个简单的演示。
#include <any>
void func() { }
auto main() -> int {
std::any a = (void*)func;
std::any_cast<void(*)()>(a)();
return 1;
}
gcc 版本 10.1.0 (GCC)
std::any_cast
只会转换回 std::any
中存储的类型。如dlsym
returnsvoid*
,就是存储在std::any
.
中的内容
在存储到 std::any
之前或在 std::any_cast
:
之后,您需要单独转换为 void(*)()
std::unordered_map<std::string_view, std::any> symbols_;
symbols_["foo"] = reinterpret_cast<void(*)()>(dlsym(handle_), "foo"));
return (std::any_cast<void(*)()>(symbols_["foo"]))();
这里你在std::any
对象中存储了一个void*
:
symbols_["foo"] = dlsym(handle_, "foo");
要改为存储 void(*)()
,您需要转换 dlsym
返回的 void*
:
symbols_["foo"] = reinterpret_cast<void(*)()>(dlsym(handle_, "foo"));
在这种情况下,您可能只想存储 void*
并在使用它时进行转换:
std::unordered_map<std::string_view, void*> symbols_;
symbols_["foo"] = dlsym(handle_, "foo");
//...
return reinterpret_cast<void(*)()>(symbols_["foo"])();
如果您不需要在 unordered_map
中进行运行时查找,第三种选择是将函数指针存储在命名变量中。这使得使用起来更容易一些。这是一个例子:
loading/unloading 共享库的通用 class
:
class Lib {
public:
explicit Lib(const char* filename, int flags = RTLD_LAZY) :
lib(dlopen(filename, flags))
{
if(!lib) throw std::runtime_error(dlerror());
}
Lib(const Lib&) = delete;
Lib(Lib&& rhs) = delete;
Lib& operator=(const Lib&) = delete;
Lib& operator=(Lib&& rhs) = delete;
virtual ~Lib() { dlclose(lib); }
private:
struct cast_proxy { // a class to cast to the proper pointer
// cast to whatever that is needed:
template<class Func>
operator Func () { return reinterpret_cast<Func>(sym); }
void* sym;
};
protected:
cast_proxy sym(const char* symbol) const {
void* rv = dlsym(lib, symbol);
if(rv) return {rv}; // put it in the cast_proxy
throw std::runtime_error(dlerror());
}
private:
void* lib;
};
A class 用于加载特定的共享库:
class YourLib : public Lib {
public:
YourLib() : Lib("./libyour_library.so"),
// load all symbols here:
foo(sym("foo")) // the cast proxy will return the correct pointer type
{}
// Definitions of all the symbols you want to load:
void(*const foo)();
};
那么使用起来就这么简单:
int main() {
YourLib ml;
ml.foo();
}
下面是我写的代码,
std::unordered_map<std::string_view, std::any> symbols_;
symbols_["foo"] = dlsym(handle_), "foo");
当我使用 any_cast
return (std::any_cast<void(*)()>(symbols_["foo"]))();
,程序会报错:bad any_cast.
我找到主要原因是因为函数.
template<typename _Tp>
void* __any_caster(const any* __any)
判断条件为false然后returnnullptr.
else if (__any->_M_manager == &any::_Manager<_Up>::_S_manage
#if __cpp_rtti
|| __any->type() == typeid(_Tp)
#endif
){
any::_Arg __arg;
__any->_M_manager(any::_Op_access, __any, &__arg);
return __arg._M_obj;
}
return nullptr;
我想知道
1.why __any->_M_manager == &any::_Manager<_Up>::_S_manage
和 __any->type() == typeid(_Tp)
都是假的,
2.and我该如何解决这个问题(继续使用std::any)。
这是一个简单的演示。
#include <any>
void func() { }
auto main() -> int {
std::any a = (void*)func;
std::any_cast<void(*)()>(a)();
return 1;
}
gcc 版本 10.1.0 (GCC)
std::any_cast
只会转换回 std::any
中存储的类型。如dlsym
returnsvoid*
,就是存储在std::any
.
在存储到 std::any
之前或在 std::any_cast
:
void(*)()
std::unordered_map<std::string_view, std::any> symbols_;
symbols_["foo"] = reinterpret_cast<void(*)()>(dlsym(handle_), "foo"));
return (std::any_cast<void(*)()>(symbols_["foo"]))();
这里你在std::any
对象中存储了一个void*
:
symbols_["foo"] = dlsym(handle_, "foo");
要改为存储 void(*)()
,您需要转换 dlsym
返回的 void*
:
symbols_["foo"] = reinterpret_cast<void(*)()>(dlsym(handle_, "foo"));
在这种情况下,您可能只想存储 void*
并在使用它时进行转换:
std::unordered_map<std::string_view, void*> symbols_;
symbols_["foo"] = dlsym(handle_, "foo");
//...
return reinterpret_cast<void(*)()>(symbols_["foo"])();
如果您不需要在 unordered_map
中进行运行时查找,第三种选择是将函数指针存储在命名变量中。这使得使用起来更容易一些。这是一个例子:
loading/unloading 共享库的通用 class
:
class Lib {
public:
explicit Lib(const char* filename, int flags = RTLD_LAZY) :
lib(dlopen(filename, flags))
{
if(!lib) throw std::runtime_error(dlerror());
}
Lib(const Lib&) = delete;
Lib(Lib&& rhs) = delete;
Lib& operator=(const Lib&) = delete;
Lib& operator=(Lib&& rhs) = delete;
virtual ~Lib() { dlclose(lib); }
private:
struct cast_proxy { // a class to cast to the proper pointer
// cast to whatever that is needed:
template<class Func>
operator Func () { return reinterpret_cast<Func>(sym); }
void* sym;
};
protected:
cast_proxy sym(const char* symbol) const {
void* rv = dlsym(lib, symbol);
if(rv) return {rv}; // put it in the cast_proxy
throw std::runtime_error(dlerror());
}
private:
void* lib;
};
A class 用于加载特定的共享库:
class YourLib : public Lib {
public:
YourLib() : Lib("./libyour_library.so"),
// load all symbols here:
foo(sym("foo")) // the cast proxy will return the correct pointer type
{}
// Definitions of all the symbols you want to load:
void(*const foo)();
};
那么使用起来就这么简单:
int main() {
YourLib ml;
ml.foo();
}