在运行时根据某些元数据强制转换参数包值

Cast parameter pack values at runtime depending on some metadata

本文关键字:转换 参数 包值 元数据 运行时      更新时间:2023-10-16

我整理了一个类来处理共享库的跨平台加载(Windows上的LoadLibrary/GetProcAddress和Linux上的dlopen/dlsym)。调用函数如下所示 -

template <typename ReturnT, typename... Args>
ReturnT Call(const std::string& name, Args... args)
{
        void* functionAddress = GetFunctionAddress(name);
        typedef ReturnT(CALLING_CONVENTION * variadicFunctionPointer)(Args...);
        auto functionPointer = reinterpret_cast<variadicFunctionPointer>(functionAddress);
        const auto returnValue = (*functionPointer)(std::forward<Args>(args)...);
        return returnValue;
}

用法如下 -

 Library someLib("someLib.dll");
 auto ret = someLib.Call<bool>("SomeCall", "StringParam", 1, true, nullptr, nullptr);   

这很好用,但我陷入困境的是尝试在运行时动态转换每个参数。 我想获取一些 json,加载相关的库,强制转换每个参数(我们从 json 中知道参数类型),然后进行调用。

 auto result = someLib.Call<bool>(function,
        std::stoi(params.at(0)["value"].get<std::string>()),
        reinterpret_cast<const uint8_t*>(params.at(1)["value"].get<std::string>().c_str()),
        std::stoi(params.at(2)["value"].get<std::string>()),
        digest.data(),
        &bufferSize);

我尝试在每个参数包参数上使用转换函数,但这不起作用,因为它需要不同的返回类型。

使用 C++14 可以这样做吗?

使用 std::variant (C++17),您可以执行以下操作:

template <typename Ret>
struct Caller
{
    Caller(const std::string& name) : name(name) {}
    template <typename ... Ts>
    Ret operator ()(Ts... args) const
    {
        void* functionAddress = GetFunctionAddress(name);
        using Func =  Ret(Ts...);
        auto functionPointer = reinterpret_cast<Func*>(functionAddress);
        return (*functionPointer)(std::forward<Ts>(args)...);
    }
    std::string name;
};

然后:

// Variant constructed from json
std::variant<int, std::string> s{"Hello"};
std::variant<int, std::string> a{40};
std::variant<int, std::string> b{2};
std::visit(Caller<void>("print"), s);
std::cout << std::visit(Caller<int>("add"), a, b) << std::endl;

演示