2011-12-23 3 views
11

Quando si compila (Microsoft Visual C++ 2005 Express) questo pezzo di codice:Impossibile convertire da tipo x a tipo x?

struct A 
{ 
    template< typename T > static A Foo(void) { return A(); } 
    struct S 
    { 
     template< typename T > static S GetInstance(void) 
     { 
      S Result; 
      Result.m_funcFoo = &A::Foo<T>; 
      return Result; 
     } 
     A (*m_funcFoo)(void); 
    }; 
}; 

int main(int argc, char* argv[]) 
{ 
    A::S::GetInstance<int>(); 
} 

ottengo un errore di C2440:

'=': cannot convert from 'A (__cdecl *)(void)' to 'A (__cdecl *)(void)'

che non ha senso per me. I due tipi nominati nel testo dell'errore sono ovviamente uguali. Inoltre, quando si modifica il valore di ritorno di Foo su int, non si verifica tale errore.

È un errore o sto facendo qualcosa di sbagliato?

MODIFICA: Quindi, se si tratta di un bug, qualcuno sa come risolvere questo? Forse usando i calchi? Ho bisogno di questo codice per compilare ...

+4

È un bug! [....] –

+0

Inizialmente, ho pensato che è perché 'A (*) (void)' * è diverso * da 'A (A :: *) (void)', ma non potrei farlo in quel modo – Griwes

risposta

4

È un bug del compilatore. VC++ sta facendo qualcosa di molto strano.

Ad esempio, questo genera un messaggio di errore molto diverso:

struct A 
{ 
    template< typename T > static struct A Foo(void) { return A(); } 
    struct S 
    { 
     template< typename T > static S GetInstance(void) 
     { 
      S Result; 
      Result.m_funcFoo = &A::Foo<T>; 
      return Result; 
     } 
     A (*m_funcFoo)(void); 
    }; 
}; 

sourceFile.cpp(5) : error C3856: 'A::Foo': class is not a class template 

E questo funziona:

struct X {}; 

struct A 
{ 
    template< typename T > static X Foo(void) { return X(); } 
    struct S 
    { 
     template< typename T > static S GetInstance(void) 
     { 
      S Result; 
      Result.m_funcFoo = &A::Foo<T>; 
      return Result; 
     } 
     X (*m_funcFoo)(void); 
    }; 
}; 

Chiaramente è sempre confuso con il nome A, che dovrebbe fare riferimento alla classe di base.

L'aggiunta di un typedef non è stata di aiuto, né una dichiarazione in avanti di struct A, né qualifica il nome come ::A o struct A.

Stranamente, VC++ 7 lo compila bene.

Soluzione: La modifica in questo modo:

struct A 
{ 
    template< typename T > static A Foo(void) { return A(); } 

    struct S; 
}; 

struct A::S 
{ 
    template< typename T > static S GetInstance(void) 
    { 
     S Result; 
     Result.m_funcFoo = &A::Foo<T>; 
     return Result; 
    } 
    A (*m_funcFoo)(void); 
}; 

inverte il risultato, ora VC++ 8 compila ok e VC++ 7 genera lo stesso messaggio di errore.

Penso che ci sia un problema di identità di tipo tra un tipo incompleto e lo stesso tipo dopo il completamento.

Tutti i test eseguiti utilizzando il Dinkumware Multi-Compiler Test Tool

1

Non sono sicuro se si tratta di un errore del compilatore o meno, ma almeno è documentato su msdn.
Non ho un compilatore 2005 a portata di mano, ma VS2010 compila il codice se scrivere in questo modo:

struct A 
{ 
    template< typename T > static A Foo(void) { return A(); } 
    struct S 
    { 
     A (*m_funcFoo)(void);  

     template< typename T > static S GetInstance(void); 
    }; 
}; 

template< typename T > 
A::S A::S::GetInstance(void) 
{ 
    S Result; 
    Result.m_funcFoo = &A::Foo<T>; 
    return Result; 
} 
+0

Oh, il collegamento MSDN è in tedesco. – fefe

+0

@fefe non più non è – AakashM

+0

@mkaes In realtà hai istanziato 'A :: S :: GetInstance' (ad esempio chiamandolo)? Ho testato il tuo codice sia in VS2005 che in VS2010: è sempre lo stesso errore. – Baltram

0

ho cercato di rintracciare il problema verso il basso e ora sembra che non è nemmeno necessario avere funzioni templated o struct nidificato per la produzione di questo strano errore.

struct A 
{ 
    typedef A (* SimpleFuncPtr)(void); 
    static void Foo(void) 
    { 
     SimpleFuncPtr func1 = 0;  // Ok. 
     SimpleFuncPtr func2 = func1; // Ok. 
     A (* func3)(void) = func1; // C2440 on both VS2005 and VS2010 
    } 
}; 

Osservando il pezzo sopra del codice diventa evidente che è davvero un bug del compilatore (a mio parere).

+0

Il problema è con il tipo incompleto, ed è descritto nel link fornito da mkaes (cioè perché il tipo è incompleto al momento della definizione del puntatore di funzione il compilatore sceglie una particolare convenzione di chiamata che viene successivamente sovrascritta quando viene definito il tipo completo) –