C ++ pointer-cursor template output does not compile when targeting x86, but works with x64

I have this code example:

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; } 

This compiles with g++ . It also compiles fine with VC10, but only when created for a 64-bit platform. When I build for a 32-bit platform, I get this compilation error:

 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> ] 

The error indicates that a non-specialized version of Gobstopper is being used, which means that Signature is something else that int (void) . But this error also clearly states that Signature is int (void) . So where does the error come from? And how can I fix this?

The only thing I can think of that can change from 32-bit to 64-bit and not appear in the signature displayed in the error message is the calling convention; there seems to be a single calling convention for VC x64, while for x86 each calling convention is different . But even if this problem, I have no idea how to fix it.

Help!

Edit: I have to mention that I tried this with the usual function pointers (not included), and that worked fine.

+6
source share
1 answer

You are absolutely right. The Signature type for Win32 target is int __thiscall(void) , and on x64, int __cdecl(void) . Note that for any purpose, the non-member type, usually called int(void) , is really int __cdecl(void) , so coincidentally one of the constructed types corresponds (not entirely correct!).

In general, it is not practical to mix different types of function pointers using template magic, so the Gobstopper specialization should look for int (ClassType::*)() instead.

+5
source

Source: https://habr.com/ru/post/910854/


All Articles