簡體   English   中英

將 void* 轉換為函數指針時,std::any_cast 拋出錯誤的 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)

它會判斷條件為假,然后返回 nullptr。

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.為什么__any->_M_manager == &any::_Manager<_Up>::_S_manage__any->type() == typeid(_Tp)都是假的,

2.我該如何解決這個問題(繼續使用 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)

在這里,您將void*存儲在std::any對象中:

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進行運行時查找,則第三個選項是將函數指針存儲在命名變量中。 這使得使用更容易一些。 下面是一個例子:

用於加載/卸載共享庫的通用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;
};

用於加載特定共享庫的類:

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::any_cast只會轉換回存儲在std::any 由於dlsym返回void* ,這就是存儲在std::any

在存儲在std::any或在std::any_cast之后,您需要對void(*)()進行單獨的std::any_cast

std::unordered_map<std::string_view, std::any> symbols_;
symbols_["foo"] = reinterpret_cast<void(*)()>(dlsym(handle_), "foo"));
return (std::any_cast<void(*)()>(symbols_["foo"]))();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM