繁体   English   中英

在 c++ 中将 function 返回类型指定为模板参数

[英]Specify function return type as template parameter in c++

我试图给我的 function 一个模板参数的返回类型(以改进类型检查),这是一个 function 参考。 这是我到目前为止所尝试的:

#include <Windows.h>

template <typename func>
decltype(auto) proxyFunction(LPCSTR dllPath, LPCSTR functionName){
    auto funcType = decltype(func);

    funcType funcPtr = (funcType) GetProcAddress(LoadLibraryA(dllPath), functionName);

    if(funcPtr)
        std::cout << "Proxy success" << std::endl;
    else
        std::cout << "Proxy fail" << std::endl;
    
    return funcPtr;
}

BOOL GetFileVersionInfoProxy(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData){
    auto getFileVersion = proxyFunction<GetFileVersionInfoProxy>("C:\\Windows\\System32\\Version.dll", "GetFileVersionInfoA");
    getFileVersion(lptstrFilename, dwHandle, dwLen, lpData);
}

但是,我收到以下关于proxyFunction的编译时错误:

没有 function 模板的实例与参数列表参数类型匹配:(const char [32], const char [20])

我不太确定如何处理这个错误,因为它相当模糊。 所以我想知道是否有人可以解释我的片段中的问题是什么?

PS 我正在使用带有 C++ 17 标准的 MS VS 2019,以防万一。

您的func模板参数已经是您要返回的类型,所以直接使用它,不需要使用decltype(auto) 以及您对auto funcType = decltype(func);的使用完全错了。

试试这个:

template <typename funcType>
funcType proxyFunction(LPCSTR dllPath, LPCSTR functionName)
{
    funcType funcPtr = (funcType) GetProcAddress(LoadLibraryA(dllPath), functionName);

    if (funcPtr)
        std::cout << "Proxy success" << std::endl;
    else
        std::cout << "Proxy fail" << std::endl;
    
    return funcPtr;
}

BOOL GetFileVersionInfoProxy(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData)
{
    using GetFileVersionInfoA_FuncType = BOOL (WINAPI *)(LPCSTR, DWORD, DWORD, LPVOID);

    auto getFileVersion = proxyFunction<GetFileVersionInfoA_FuncType>("C:\\Windows\\System32\\Version.dll", "GetFileVersionInfoA");
    if (getFileVersion)
        return getFileVersion(lptstrFilename, dwHandle, dwLen, lpData);

    return FALSE;
}

或者,如果让编译器为您推导出模板参数,则可以省略传递:

template <typename funcType>
bool proxyFunction(LPCSTR dllPath, LPCSTR functionName, funcType &funcPtr)
{
    funcPtr = (funcType) GetProcAddress(LoadLibraryA(dllPath), functionName);

    if (funcPtr)
        std::cout << "Proxy success" << std::endl;
    else
        std::cout << "Proxy fail" << std::endl;
    
    return (funcPtr != nullptr);
}

BOOL GetFileVersionInfoProxy(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData)
{
    using GetFileVersionInfoA_FuncType = BOOL (WINAPI *)(LPCSTR, DWORD, DWORD, LPVOID);

    GetFileVersionInfoA_FuncType getFileVersion;
    if (proxyFunction("C:\\Windows\\System32\\Version.dll", "GetFileVersionInfoA", getFileVersion))
        return getFileVersion(lptstrFilename, dwHandle, dwLen, lpData);

    return FALSE;
}

更新:根据@MooingDuck 的评论,看起来您实际上是在尝试将您的代理 function 传递给模板,并让它推断出必要的参数和返回类型以用于 DLL ZC1C4245268E687A94D1 如果是这样,请尝试更多类似的方法:

template <typename RetType, typename... ArgTypes>
struct proxyTraits
{
    using funcType = RetType (WINAPI *)(ArgTypes...);
};

template <typename RetType, typename... ArgTypes>
auto proxyFunction(
    LPCSTR dllPath,
    LPCSTR functionName,
    RetType (*proxy)(ArgTypes...))
{
    using funcType = typename proxyTraits<RetType, ArgTypes...>::funcType;
    funcType funcPtr = (funcType) GetProcAddress(LoadLibraryA(dllPath), functionName);

    if (funcPtr)
        std::cout << "Proxy success" << std::endl;
    else
        std::cout << "Proxy fail" << std::endl;
    
    return funcPtr;
}

BOOL GetFileVersionInfoProxy(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData)
{
    auto getFileVersion = proxyFunction("C:\\Windows\\System32\\Version.dll", "GetFileVersionInfoA", &GetFileVersionInfoProxy);
    if (getFileVersion)
        return getFileVersion(lptstrFilename, dwHandle, dwLen, lpData);

    return FALSE;
}

现场演示

所以事实证明std::function实现了我正在寻找的那种行为。

例如,如果我的虚拟 DLL function 定义如下:

#include <Windows.h>

#define DllExport extern "C"  __declspec( dllexport )

DllExport int SQUARE(int number){
    return number * number;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved){
    return TRUE;
}

然后我会按如下方式导入它:

#include <Windows.h>
#include <iostream>
#include <functional>

HMODULE dummyHandle = nullptr;

template<typename signature>
std::function<signature> proxyFunction(HMODULE hModule, LPCSTR functionName){
    auto funcPtr = GetProcAddress(hModule, functionName);
    std::cout << (funcPtr ? "Proxy success" : "Proxy fail") << std::endl;
    return std::function<signature>(reinterpret_cast<signature*>(funcPtr));
}

int SQUARE(int number){
    auto proxy = proxyFunction<decltype(SQUARE)>(dummyHandle, __FUNCTION__);
    return proxy ? proxy(number) : -1;
}

int main(){
    dummyHandle = LoadLibraryA("C:\\Absolute\\Path\\To\\Dummy.dll");
    if(dummyHandle)
        std::cout << "Square of 7 is " << SQUARE(7) << std::endl;
    else
        std::cout << "Failed to load dummy dll. Last Error: " << GetLastError() <<std::endl;

    system("pause");
}

我喜欢这种方法,因为它无需定义辅助构造即可启用基本的 static 类型检查。 但是,我仍然认为还有改进的余地。 每次调用proxyFunction时,我们都必须将 function 包装到decltype(...)中。 有谁知道如何以简单的方式在proxyFunction中隐藏该位?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM