Pytanie Nie można przekonwertować z typu x na typ x?


Podczas kompilacji (Microsoft Visual C ++ 2005 Express) ten fragment kodu:

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:

"=": nie można przekonwertować z "A (__cdecl *) (void)" na "A (__cdecl *) (void)"

To nie ma dla mnie sensu. Dwa typy nazwane w tekście błędu są oczywiście takie same. Również przy zmianie Foozwraca wartość do int, nie ma takiego błędu.

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

EDYTOWAĆ : 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 ...


11
2017-12-23 15:31


pochodzenie


To błąd! [....] - Prasoon Saurav
Na początku myślałem, że to dlatego A (*)(void)  jest inny od A (A::*)(void), ale nie mógł tego zrobić w ten sposób. - Griwes


Odpowiedzi:


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

Na przykład generuje to bardzo 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

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

Najwyraźniej to się myli z tym imieniem A, co powinno odnosić się do klasy bazowej.

Dodanie typedef nie pomogło, ani nie przekazuje deklaracji struct A, ani nie kwalifikuje się jako nazwa ::A lub struct A.

Dziwne, VC ++ 7 kompiluje to dobrze.

Obejście: Zmiana w następujący sposób:

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 wynik, teraz VC ++ 8 kompiluje ok, a VC ++ 7 generuje ten sam komunikat o błędzie.

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

Wszystkie testy są uruchamiane przy użyciu Dinkumware Multi-Compiler Test Tool


4
2017-12-23 17:55





Nie jestem pewien, czy jest to błąd kompilatora, czy nie, ale przynajmniej jest to udokumentowane msdn.
Nie mam pod ręką kompilatora z 2005 roku, ale vs2010 kompiluje twój kod, jeśli napisze 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;
}

1
2017-12-23 16:16



Oh, łącze MSDN jest w języku niemieckim. - fefe
@fefe już nie, nie jest - AakashM
@mkaes Czy faktycznie tworzysz instancję? 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


Wygląda jak błąd - kompiluje się dobrze na Comeau (http://www.comeaucomputing.com/tryitout).


1
2017-12-23 16:33





Próbowałem wyśledzić problem, a teraz wydaje się, że nie jest nawet konieczne posiadanie szablonowych funkcji lub zagnieżdżonych struktur w celu wygenerowania tego dziwnego błędu.

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
2017-12-23 18:03



Problem dotyczy niekompletnego typu i jest opisany w łączu dostarczonym przez mkaes (to znaczy, 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) - David Rodríguez - dribeas