6

私はこのサンプルコードを持っています:

struct A
{
    int foo() { return 27; }
};

template<typename T>
struct Gobstopper
{
};

template<>
struct Gobstopper<int(void)>
{
    Gobstopper(int, int) { }    // To differentiate from general Gobstopper template
};

template<typename ClassType, typename Signature>
void DeduceMethodSignature(Signature ClassType::* method, ClassType& instance)
{
    // If Signature is int(), Gobstopper<> should resolve to the specialized one.
    // But it only does on x64!
    Gobstopper<Signature>(1, 2);
}

int main(int argc, char** argv)
{
    A a;
    DeduceMethodSignature(&A::foo, a);

    return 0;
}

これは で問題なくコンパイルされg++ます。VC10 でも問題なくコンパイルできますが、64 ビット プラットフォーム用にビルドする場合のみです。32 ビット プラットフォーム用にビルドすると、次のコンパイル エラーが発生します。

error C2661: 'Gobstopper<T>::Gobstopper' : no overloaded function takes 2 arguments
1>          with
1>          [
1>              T=int (void)
1>          ]
1>          c:\...\test.cpp(26) : see reference to function template instantiation 'void DeduceMethodSignature<A,int(void)>(Signature (__thiscall A::* ),ClassType &)' being compiled
1>          with
1>          [
1>              Signature=int (void),
1>              ClassType=A
1>          ]

このエラーは、特殊化されていないバージョンの Gobstopper が使用されていることを示してSignatureint (void)ます。Signature しかし、エラーはそれが であることも明確に示していますint (void)。では、エラーはどこから来るのでしょうか? どうすれば修正できますか?

32 ビットから 64 ビットに変更され、エラー メッセージに表示される署名に表示されない可能性がある唯一のことは、呼び出し規約です。どうやら、VC x64 には統一された呼び出し規約がありますが、x86 ではそれぞれの呼び出し規約が異なります。しかし、それが問題だとしても、それを修正する方法がわかりません。

編集:通常の(非メンバー)関数ポインターでこれを試したところ、うまくいきました。

4

1 に答える 1

5

あなたはかなり正しいです。SignatureWin32 ターゲットの のタイプはint __thiscall(void)、x64 では ですint __cdecl(void)。どちらのターゲットでも、一般的に呼び出される非メンバー関数の型int(void)は実際にint __cdecl(void)そうであることに注意してください。偶然にも、構築された型の 1 つが実際に (実際には正確ではありません!) 一致します。

一般に、テンプレート マジックによって異なるタイプの関数ポインターを混在させることはお勧めできませんint (ClassType::*)()

于 2012-03-15T23:33:44.857 に答える