Вычисление шаблона указателя на метод в C ++ не компилируется при нацеливании на x86, но работает с x64 - PullRequest
6 голосов
/ 16 марта 2012

У меня есть этот пример кода:

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, что должно означать, что Signature является чем-то другимэто int (void).Но ошибка также ясно говорит о том, что Signature есть int (void).Так откуда берется ошибка?И как я могу это исправить?

Единственное, что я могу придумать, это может измениться с 32-разрядного на 64-разрядное и не отображаться в сигнатуре, отображаемой в сообщении об ошибке, это соглашение о вызовах;по-видимому, существует унифицированное соглашение о вызовах для VC x64, тогда как для x86 каждое соглашение о вызовах отличается .Но даже если это проблема, я понятия не имею, как это исправить.

Редактировать: я должен упомянуть, что я пробовал это с обычными (не членами) указателями на функции, и это работало нормально.

1 Ответ

5 голосов
/ 16 марта 2012

Вы совершенно правы. Тип Signature с целью Win32 - int __thiscall(void), а на x64 - int __cdecl(void). Обратите внимание, что для любой цели тип функций, не являющихся членами, обычно называемых int(void), действительно int __cdecl(void), поэтому, по совпадению, один из созданных типов действительно (не совсем правильно!) Совпадает.

В общем случае не рекомендуется смешивать различные типы указателей функций с помощью магии шаблонов, поэтому специализация Gobstopper должна выглядеть примерно так: int (ClassType::*)().

...