簡體   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