Tengo este código de ejemplo:C++ deducción plantilla-puntero a método no compila cuando la orientación x86, x64, pero trabaja con
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;
}
Este compila bien con g++
. También compila bien con VC10, pero solo cuando se compila para la plataforma de 64 bits. Cuando construyo para la plataforma de 32 bits, consigo este error de compilación:
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> ]
El error indica que se está utilizando la versión no especializado de chicle, que debe significar la Signature
es algo más que int (void)
. Pero el error también dice claramente que Signature
esint (void)
. Entonces, ¿de dónde viene el error? ¿Y cómo puedo solucionarlo?
Lo único que se me ocurre que podría cambiar de 32 bits a 64 bits y no aparecer en la firma que se muestra en el mensaje de error es la convención de llamadas; aparentemente, there is a unified calling convention for VC x64, whereas for x86 each calling convention is distinct. Pero incluso si ese es el problema, no tengo idea de cómo solucionarlo.
¡Ayuda!
Editar: Debo mencionar que probé esto con punteros de función regulares (no miembros), y que funcionó bien.
Hmm. Gracias por confirmar mis sospechas (¿cómo revisaste, por cierto? Me parece bastante complicado depurar argumentos de plantilla). ¿Hay alguna manera de separar la convención de llamadas de 'Firma'? Realmente no uso 'T' dentro de Gobstopper para definir un puntero a la función, simplemente como un medio para desambiguar las especializaciones de las plantillas. Además, no para criticar (OK, para Nitpick), pero tampoco es la convención de llamadas en x64 '__thiscall', pero pasa a ser compatible con' __cdecl'? – Cameron
En realidad, la convención de 32 bits para VC++ es cdecl para funciones "normales" y esto llama para funciones de miembros. En Windows de 64 bits, ni el cdecl ni el llamado son conocidos del entorno de 32 bits, pero hay algo diferente que utiliza incluso más registros que este llamado para ambos tipos. Si desea obtener más información, considere consultar http://www.agner.org/optimize/calling_conventions.pdf donde se enumeran prácticamente todas las convenciones de llamadas en uso. –
Ah, y en VS puede usar 'typeid (T) .name()' para darle el nombre de un tipo, incluso si es un argumento de plantilla. –