有没有一种方法可以在容器中存储不同的函数指针类型?

Is there a way to store different function pointer types in a container

本文关键字:存储 函数 类型 指针 一种 方法 有没有      更新时间:2023-10-16

在下面的代码中,我试图将函数指针存储在向量中,但每个函数指针都有不同的签名。

下面代码的思想是,当我加载一个DLL时,我只是使用一个循环将DLL中的所有函数加载到vector中。然后,当我想调用一个函数时,我只需通过名称或索引调用它,并传递一个可变数量的参数。但是我真的希望调用函数的方式和加载它们的方式一样:通过循环。

#if defined _WIN32 || defined _WIN64
#include <windows.h>
#else
#include <dlfcn.h>
#endif
#include <iostream>
#include <cstdint>
#include <vector>
#include <functional>
class Library
{
    private:
        void* Module;
    public:
        Library(std::string Library);
        ~Library();
        template<typename T>
        T AddressOf(std::string FunctionName);
        template<typename T>
        bool AddressOf(T &FunctionDefinition, std::string FunctionName);
        template<typename T, typename ...Args>
        auto CallFunction(void* Function, Args... args) -> decltype(reinterpret_cast<T>(Function)(args...));
};
Library::Library(std::string Library)
{
    #if defined _WIN32 || defined _WIN64
    this->Module = LoadLibrary(Library.c_str());
    #else
    this->Module = dlopen(Library.c_str(), RTLD_LAZY);
    #endif
}
Library::~Library()
{
    #if defined _WIN32 || defined _WIN64
    FreeLibrary(static_cast<HMODULE>(this->Module));
    #else
    dlclose(this->Module);
    #endif
}
template<typename T>
T Library::AddressOf(std::string FunctionName)
{
    #if defined _WIN32 || defined _WIN64
    return reinterpret_cast<T>(GetProcAddress(static_cast<HMODULE>(this->Module), FunctionName.c_str()));
    #else
    return reinterpret_cast<T>(dlsym(this->Module, FunctionName.c_str()));
    #endif
}
template<typename T>
bool Library::AddressOf(T &FunctionDefinition, std::string FunctionName)
{
    return (FunctionDefinition = this->AddressOf<T>(FunctionName));
}
template<typename T, typename ...Args>
auto Library::CallFunction(void* Function, Args... args) -> decltype(reinterpret_cast<T>(Function)(args...))
{
    return reinterpret_cast<T>(Function)(args...);
}


std::vector<void*> Functions;
typedef void (*Message)(const LPCSTR sometext);
typedef void (*MessageEx)(const LPCSTR sometext, const LPCSTR title);
typedef int (*Add)(int X, int Y);
typedef int (*Subtract)(int X, int Y);
int main()
{
    Library L("TestDll.dll");
    std::array<std::string, 4> List = {"Message", "MessageEx", "Add", "Sub"};
    /** Get Function Addresses.. **/
    for (std::size_t I = 0; I < List.size(); ++I)
    {
        Functions.push_back(L.AddressOf<void*>(List[I]));
    }
    /** Call Functions.. **/
    L.CallFunction<Message>(Functions[0], "Hello World!");
    L.CallFunction<MessageEx>(Functions[1], "Hello World!", "DLL MessageBox Title");
    std::cout<<L.CallFunction<Add>(Functions[2], 5, 7)<<"n";
    std::cout<<L.CallFunction<Subtract>(Functions[3], 7, 5)<<"n";
    return 0;
}

是否有更好的方法来重写我的CallFunction类成员,或者以某种方式保留函数签名或将函数名称映射到其签名?我不介意写出类型定义,但我讨厌把它们作为模板参数,以便它可以强制转换,所以如果我能以某种方式让向量存储不同的函数签名将是最好的,但任何解决方案都是受欢迎的。

EDIT:为了说清楚,我想以某种方式找出给定其参数的函数签名。例:

//If I do:
CallFunction<int>(FuncPtr, "Subtract", 10, 5);
//It would do:

template<typename T, typename ...Args>
auto Library::CallFunction(void* Function, Args... args) -> decltype(reinterpret_cast<T>(Function)(args...))
{
    return  //using args, figure out the function signature, call it, and return int.
}

对我来说,这似乎很做作。你需要在正确的地方有正确的函数,有正确的参数,有正确的名字。如果你声明了一个函数指针typedef,并使用单行reinterpret_cast来赋值函数,那么你需要40多个函数才能完成你在这里提供的代码——这是简单的步骤和重复类型代码,所以很容易遵循和维护。没有模板,没有变量参数,等等

显然,您仍然需要生成一个从名称返回void *的函数。这就是减去reinterpret_cast的结果。