6

__cdecl私の目標は、呼び出し規約と呼び出し規約の両方を使用して、任意の関数のプロトタイプを簡単に抽出すること__stdcallです。32ビットで問題なく動作します。変更されている唯一のことは、テンプレート関数パラメーターの呼び出し規約です。

ウィキペディアによると:

Windows コンテキストで x64 アーキテクチャ用にコンパイルする場合 (Microsoft のツールを使用するか、Microsoft 以外のツールを使用するかに関係なく)、呼び出し規約は 1 つだけです。ここで説明するものであるためstdcallthiscallcdeclfastcallなどはすべて同じものになります。

これにより、64 ビットのコードが壊れます。呼び出し規則は同じですが、関数をパラメーターとして渡すには、正しい命名法を使用する必要があります。IE で関数が として定義されている場合は__stdcall、それを受け入れるラッパーに渡す必要があります__stdcall。は同一ですが、を受け入れるラッパーに対して__cdecl定義された関数を渡す必要があります。__cdecl__cdecl

32 ビットで動作する例:

template<typename T, typename... Args>
struct WrapperSTD { typedef T(__stdcall *Functor)(Args...); };

template<typename T, typename... Args>
struct WrapperC { typedef T(*Functor)(Args...); };

template<typename T, typename... Args>
WrapperSTD<T, Args...> wrap(T(__stdcall *func)(Args...)) {
    return WrapperSTD<T, Args...>{};
}
template<typename T, typename... Args>
WrapperC<T, Args...> wrap(T(*func)(Args...)) {
    return WrapperC<T, Args...>{};
}

私の目標は、たとえば次のように実行できるようにすることでした。

using MsgBoxProto = decltype(wrap(MessageBoxA))::Functor;

これは 32 ビットでは問題ありません。ただし、 x64 では__stdcall__cdeclは明らかに同一であるため、64 ビットでは機能せず、呼び出しが曖昧であるというエラーが発生します。また、テンプレートが既に定義されていることもわかります。直観的には、コンパイラはそれらを同一と見なすため、関数__cdeclをこの関数に渡すことができるように思えます。__stdcallただし、これは機能しません。

template<typename T, typename... Args>
struct WrapperFC { typedef T(__stdcall *Functor)(Args...); };

template<typename T, typename... Args>
WrapperFC<T, Args...> wrap(T(__stdcall *func)(Args...)) {
    return WrapperFC<T, Args...>{}; // same as below
}

template<typename T, typename... Args>
WrapperFC<T, Args...> wrap(T(__cdecl *func)(Args...)) {
    return WrapperFC<T, Args...>{}; // same as above
}

エラー C2995 'WrapperFC<T,Args...> wrap(T (__cdecl *)(Args...))': 関数テンプレートは既に定義されています

それらの 1 つだけを保持する場合、これらの関数の両方を同時にラップすることはできません。

void __cdecl foo(int i){}
void __stdcall bar(int i){}

コンパイラがそれらを同じと見なす場合、異なる呼び出し規則を受け入れるために異なるテンプレートを用意する必要があるのはなぜですか? そして、私がそうすると、なぜそれは完全に壊れて、あいまいですでに定義されていると言うのですか?

TL;DR:

64 ビット アーキテクチャの呼び出し規約が同一である場合、ある呼び出し規約を別の呼び出し規約を期待する関数に渡すことができないのはなぜですか? どうすれば修正できますか?

4

2 に答える 2