簡體   English   中英

如果Template Argument無效,請在Compile-Time檢查

[英]Check at Compile-Time if Template Argument is void

我正在嘗試包裝Windows API函數以在我選擇時檢查錯誤。 正如我在之前的SO問題中發現的那樣,我可以使用模板函數來調用API函數,然后調用GetLastError()來檢索它可能設置的任何錯誤。 然后我可以將此錯誤傳遞給我的Error類,讓我知道它。

這是模板函數的代碼:

template<typename TRet, typename... TArgs>
TRet Wrap(TRet(WINAPI *api)(TArgs...), TArgs... args)
{
    TRet ret = api(args...);
    //check for errors
    return ret;
}

使用這個我可以有如下代碼

int WINAPI someFunc (int param1, BOOL param2); //body not accessible

int main()
{
    int ret = someFunc (5, true); //works normally
    int ret2 = Wrap (someFunc, 5, true); //same as above, but I'll get a message if there's an error
}

這非常有效。 但是,有一個可能的問題。 采取這個功能

void WINAPI someFunc();

將其轉換為模板函數時,它看起來如下:

void Wrap(void(WINAPI *api)())
{
    void ret = api(); //<-- ahem! Can't declare a variable of type void...
    //check for errors
    return ret; //<-- Can't return a value for void either
}

為了解決這個問題,我試圖創建一個版本,我替換的模板的TRetvoid 不幸的是,這實際上只會導致使用哪一個模糊。

除此之外,我嘗試過使用

if (strcmp (typeid (TRet).name(), "v") != 0) //typeid(void).name() == "v"
{
    //do stuff with variable to return
}

else
{
    //do stuff without returning anything
}

但是, typeid是一個運行時比較,因此代碼仍然無法編譯,因為嘗試聲明一個void變量,即使它永遠不會。

接下來,我嘗試使用std::is_same <TRet, void>::value而不是typeid ,但發現它也是一個運行時比較。

此時,我不知道下一步該嘗試什么。 有沒有可能讓編譯器相信我知道我在做什么會運行正常? 我不介意給Wrap附加一個額外的參數,但我也無法從中獲得任何東西。

我使用Code :: Blocks與GNU G ++ 4.6.1,Windows XP以及Windows 7.感謝任何幫助,即使它告訴我,我必須最終只是不使用Wrap來返回返回的函數無效。

您可以使用輔助類來微調特化:

template <typename F>
struct wrapper
{};

template <typename Res, typename... Args>
struct wrapper<Res(Args...)>
{
    static Res wrap(Res (WINAPI *f)(Args...), Args&& args...)
    {
        Res r = f(std::forward<Args>(args)...);
        // Blah blah
        return r;
    }
};

template <typename... Args>
struct wrapper<void(Args...)>
{
    static void wrap(void (WINAPI *f)(Args...), Args&& args...)
    {
        f(std::forward<Args>(args)...);
        // Blah blah
    }
};

現在,您可以編寫包裝器:

template <typename Res, typename... Args>
Res Wrap(Res (WINAPI *f)(Args...), Args&& args...)
{
    return wrapper<Res(Args...)>::wrap(f, std::forward<Args>(args)...);
}

請注意,即使Res void ,它仍然有效。 你被允許return在返回void的函數表達式返回void。

推導出正確的類型,如Wrap(someFunc, 5, true) ,即使對於返回void的函數也是Wrap(someFunc, 5, true)

為了解決這個問題,我嘗試創建一個模板版本,用虛擬替換TRet。 不幸的是,這實際上只會導致使用哪一個模糊。

我相信這應該有效,因為voidTRet更專業,但正如你所指出的那樣。 我可能會遺漏一些東西,但無論如何,無關緊要,你可以防止選擇TRet重載。

template<typename TFun, typename... TArgs>
auto Wrap(TFun api, TArgs&&... args) ->
typename std::enable_if<
    !std::is_void<typename std::result_of<TFun(TArgs...)>::type>::value,
    typename std::result_of<TFun(TArgs...)>::type
>::type
{
    auto result = api(std::forward<TArgs&&>(args)...);
    return result;
}

template<typename TFun, typename... TArgs>
auto Wrap(TFun api, TArgs&&... args) ->
typename std::enable_if<
    std::is_void<typename std::result_of<TFun(TArgs...)>::type>::value,
    typename std::result_of<TFun(TArgs...)>::type
>::type
{
    api(std::forward<TArgs&&>(args)...);
}

void WINAPI f1()
{
}

void WINAPI f2(double)
{
}

int WINAPI f3()
{
    return 0;
}

int WINAPI f4(double)
{
    return 0;
}

int main() {
    Wrap(f1);
    Wrap(f2, 0);
    return Wrap(f3) * Wrap(f4, 0);
}

更新 :已調整為允許從參數類型到參數類型的轉換。

從評論到答案的推廣我理解為什么將返回類型專門化為void無法工作(不能消除返回類型的歧義)但是專注於void並添加一個額外的參數應該有效,會發生什么? 您可能必須使用顯式類型進行調用。

暫無
暫無

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

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