2011-12-23 11 views
11

Podczas kompilacji (Microsoft Visual C++ 2005 Express) to fragment kodu:Nie można przekonwertować z typu x na typ 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>(); 
} 

pojawia się błąd C2440:

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

To nie ma dla mnie sensu. Dwa typy nazwane w tekście błędu są oczywiście takie same. Ponadto, po zmianie wartości zwracanej Foo na int, nie ma takiego błędu.

Czy to błąd, czy robię coś nie tak?

EDIT: Więc, jeśli to błąd, czy ktoś wie, jak rozwiązać ten problem? Może za pomocą rzutów? Potrzebuję tego kodu do kompilacji ...

+4

To jest błąd! [....] –

+0

Początkowo myślałem, że to dlatego, że 'A (*) (void)' * jest inne * od 'A (A :: *) (void)', ale nie mógł tego zrobić w ten sposób. – Griwes

Odpowiedz

4

To błąd kompilatora. VC++ robi coś bardzo dziwnego.

Na przykład ten generuje zupełnie inny komunikat o błędzie:

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 

I to działa:

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

Wyraźnie robi się mylić z nazwą A, które powinny odnosić się do klasy bazowej.

Dodanie typedef nie pomogło, nie ma też deklaracji forward z struct A, ani nie kwalifikuje się ona jako ::A lub struct A.

Dziwne, VC++ 7 kompiluje to dobrze.

Obejście: Zmiana to tak:

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

odwraca rezultat, teraz VC++ 8 kompiluje ok i VC++ 7 generuje ten sam komunikat o błędzie.

Wydaje mi się, że istnieje problem tożsamości typu między niekompletnym typem a tym samym typem po zakończeniu.

Wszystkie testy wykonywane przy użyciu Dinkumware Multi-Compiler Test Tool

1

Nie jestem pewien, czy jest to błąd kompilatora, czy nie, ale przynajmniej jest to udokumentowane na msdn.
ja nie mam 2005 kompilatora pod ręką ale VS2010 kompiluje kod jeśli napisać to tak:

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

O, łącze MSDN jest w języku niemieckim. – fefe

+0

@fefe już nie, to nie jest – AakashM

+0

@mkaes Czy faktycznie stworzyłeś 'A :: S :: GetInstance' (na przykład przez wywołanie go)? Testowałem twój kod zarówno w VS2005, jak i VS2010 - to wciąż ten sam błąd. – Baltram

0

Starałem się śledzić ten problem w dół, a teraz wydaje się, że nie jest nawet konieczne, aby mieć na matrycy funkcji lub zagnieżdżone struktury do produkują ten dziwny błąd.

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

Patrząc na powyższy fragment kodu staje się oczywiste, że jest to rzeczywiście błąd kompilatora (moim zdaniem).

+0

Problem dotyczy niekompletnego typu i jest opisany w łączu dostarczonym przez mkaes (tzn. Ponieważ typ jest niekompletny w momencie definicji wskaźnika funkcji, kompilator wybiera konkretną konwencję wywołania, która jest później zmieniana, gdy zdefiniowany jest pełny typ) –