1

私は回り道を使用していますが、それらが使用するキャストが非常に醜いことがわかったので、キャストを行うためにいくつかのテンプレート関数を作成しました。

// Cast a function pointer to a void *
template <typename RET_TYPE, typename...ARGs>
void* fnPtrToVoidPtr(RET_TYPE(WINAPI * pOriginalFunction)(ARGs...))
{
    return (void*)pOriginalFunction;
}

// Cast a function pointer that is referencable to a void *&
template <typename RET_TYPE, typename...ARGs>
void*& fnPtrRefToVoidPtrRef(RET_TYPE(WINAPI*& pOriginalFunction)(ARGs...))
{
    return (void*&)pOriginalFunction;
}

これにより、次の呼び出しを実行できます。

BOOL (WINAPI *pDestroyIcon)(HICON) = DestroyIcon;
DetourAttach(&fnPtrRefToVoidPtrRef(pDestroyIcon), fnPtrToVoidPtr(DestroyIcon));

fnPtrRefToVoidPtrRefしかし、2 つの関数名を1 つの名前に統合できないかと考えていfnPtrToVoidPtrました。

テンプレートの引数を推測できないため、次の操作は機能しません。

// Cast a function pointer to a void *
template <typename RET_TYPE, typename...ARGs>
void* fnPtrToVoidPtr(RET_TYPE(WINAPI * & pOriginalFunction)(ARGs...))
{
    return (void*)pOriginalFunction;
}

// Cast a function pointer that is referencable to a void *&
template <typename RET_TYPE, typename...ARGs>
void*& fnPtrToVoidPtr(RET_TYPE(WINAPI * && pOriginalFunction)(ARGs...))
{
    return (void*&)pOriginalFunction;
}

BOOL (WINAPI *pDestroyIcon)(HICON) = DestroyIcon;
void* p1 = fnPtrToVoidPtr(DestroyIcon);
void** p2 = &fnPtrToVoidPtr(pDestroyIcon);

次のエラーが発生します。

// error C2784: 'void *&fnPtrToVoidPtr(RET_TYPE (__stdcall *&&)(ARGs...))' : could not deduce template argument for 'overloaded function type' from 'overloaded function type'

私の元の関数を使用すると、これは正常に機能します。

    BOOL (WINAPI *pDestroyIcon)(HICON) = DestroyIcon;
    void* p1 = fnPtrToVoidPtr(DestroyIcon);
    void** p2 = &fnPtrRefToVoidPtrRef(pDestroyIcon);

ただし、これに変更fnPtrRefToVoidPtrRefすると:

// Cast a function pointer that is referencable to a void *&
template <typename RET_TYPE, typename...ARGs>
void*& fnPtrRefToVoidPtrRef(RET_TYPE(WINAPI*&& pOriginalFunction)(ARGs...))
{
    return (void*&)pOriginalFunction;
}

次のエラーが表示されます。

error C2664: 'void *&fnPtrRefToVoidPtrRef<BOOL,HICON>(RET_TYPE (__stdcall *&&)(HICON))' : cannot convert argument 1 from 'BOOL (__stdcall *)(HICON)' to 'BOOL (__stdcall *&&)(HICON)'

テンプレート推論ができないのは、それが同じ(または変換可能?)タイプであると認識しない理由のようです。C++ を取得して関数ポインタを適切に推測する方法はありますか?

4

1 に答える 1

2

コードには 2 つの問題があります。順番に修正していきましょう。

まず、2 つのfnPtrToVoidPtrオーバーロードの本体と戻り値の型を切り替える必要があります。あなたが望むのは、キャストvoid*を介して、関数ポインタ型の左辺値を type の左辺値に変換することです(void*&)。そのため、このキャストは、* &変更可能な左辺値にバインドされるパラメータの型であり、もう一方の型です。* &&右辺値にバインドします。逆に、(void*)キャストは を受け取る関数に入る必要があります* &&。明らかに、それに応じて戻り値の型を変更する必要があります。

ここで、推論が失敗した理由:fnPtrToVoidPtr(DestroyIcon)元のバージョンのように呼び出しを行う場合、関数からポインターへの変換に依存しています。パラメーター (宛先) が参照の場合、この変換は行われません。

したがって、両方のオーバーロードが参照を取る 2 番目のバージョンでは、パラメーターはポインターへの参照ですが、引数は関数識別子です。前者のテンプレート引数は後者から推測できないため、推測は失敗します。これに対する最も簡単な修正は、次のように、呼び出しに関数ポインターを明示的に提供することですfnPtrToVoidPtr(&DestroyIcon)

&DestroyIconは右辺値であるため、* &&パラメーターはそれにバインドされますが、* &希望どおりにはバインドされません。

これら 2 つの修正により、コードのコンパイル可能なバージョンは次のようになります。

#include "windows.h"

// Cast a function pointer to a void *
template <typename RET_TYPE, typename...ARGs>
void* fnPtrToVoidPtr(RET_TYPE(WINAPI * && pOriginalFunction)(ARGs...))
{
   return (void*)pOriginalFunction;
}

// Cast a function pointer that is referencable to a void *&
template <typename RET_TYPE, typename...ARGs>
void*& fnPtrToVoidPtr(RET_TYPE(WINAPI * & pOriginalFunction)(ARGs...))
{
   return (void*&)pOriginalFunction;
}

BOOL(WINAPI *pDestroyIcon)(HICON) = DestroyIcon;

int main()
{
   void* p1 = fnPtrToVoidPtr(&DestroyIcon);
   void** p2 = &fnPtrToVoidPtr(pDestroyIcon);
}

&関数名の前に演算子を使用する必要がない場合は、a* &&を取るオーバーロードを&関数への左辺値参照 - を取るように変更することもできます。現在、そのバージョンは として呼び出すことができますfnPtrToVoidPtr(DestroyIcon)。関数への&&右辺値参照も関数の左辺値にバインドされるため (関数への右辺値参照) も機能します (関数を指定するすべての識別子式は左辺値です)。

于 2015-04-12T17:56:04.310 に答える