Вычисление шаблона указателя на метод в C++ не компилируется при нацеливании на x86, но работает с x64
У меня есть этот пример кода:
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 ответ
Вы совершенно правы. Тип Signature
с целью Win32 int __thiscall(void)
в то время как на x64 это int __cdecl(void)
, Обратите внимание, что для любой цели тип функций, не являющихся членами, обычно называется int(void)
это действительно int __cdecl(void)
так, по совпадению один из построенных типов фактически (не очень правильно!) совпадает.
В общем случае не рекомендуется смешивать различные типы указателей функций с помощью магии шаблонов, поэтому специализация Gobstopper должна выглядеть примерно так: int (ClassType::*)()
вместо.