Einlesen einer 'inner struct' eines Templates von istream compiliert nicht



  • Hallo Leute,

    ich habe folgenden Code

    #include <iostream>
    
    template< typename T >
    struct Foo {
        struct Inn {
            int m_x;
        };
        T m_y;
    };
    
    template< typename T >
    std::istream& operator>>( std::istream& in, typename Foo< T >::Inn& i ) {
        int x;
        if( in >> x ) i.m_x = x;
        return in;
    }
    
    int main() {
        Foo< int >::Inn i;
        std::cin >> i;  // <---- kompiliert nicht: 
           // no operator ">>" matches these operands
           //      operand types are: std::istream >> Foo<int>::Inn
        return 0;
    }
    

    Meine Compiler (VC7 Comeau) sind beide in der markierten Zeile der Meinung, dass es keinen operator>>( std::istream& in, Foo< int >::Inn& i ) gibt. Was mache ich falsch? Deklariere ich die Streaming-Funktion konkret mit einem int, statt als Template, so funkt's.

    Gruß
    Werner



  • Die automatische Auflösung der Templates hat irgendwo ihre Grenzen - und ganz offensichtlich hast du diese Grenzen ausgelotet.



  • wäre nett, wenn Du etwas konkreter werden könntest 😕 . Der Typ der Variable 'i' in main() ist jedenfalls glasklar definiert.

    Gruß
    Werner



  • so gehts:

    operator>><int>(std::cin, i);
    


  • in dem fall macht dir einfach 14.8.2.4 (3 und 4) einen strich durch die rechnung...



  • davie schrieb:

    in dem fall macht dir einfach 14.8.2.4 (3 und 4) einen strich durch die rechnung...

    Danke Davie,

    in 14.8.2.4 Paragraph 4 steht tatsächlich, dass das Template so nicht aufgelöst wird. Warum das so sein muss, habe ich nicht verstanden ... 😕

    Gruß
    Werner



  • Hallo,
    es handelt sich hier um einen sogenannten non-deduced Context. Der Grund für die Existenz solcher nicht herleitbaren Kontexte ist einfach der, dass sie mehrdeutigkeiten zulassen (genaugenommen kann es eine unbegrentze Anzahl von Typen geben, die den non-deduced Context erfüllen könnten).
    Klassisches Beispiel:

    template <class T> 
    struct X { typedef T Y; } 
    
    template <> 
    struct X<short> { typedef int Y; } 
    
    template <class T>
    void f( typename X<T>::Y );
    
    f( 42 ); // Ups. Mehrdeutig könnte X<int>::Y (also int) oder aber X<short>::Y (also auch int) sein.
    


  • Danke Hume für die Erklärung.

    Das mit der Mehrdeutigkeit war mir im Prinzip schon klar. Die Frage, die ich mir hier Stelle ist, wieso mein Beispiel mehrdeutig sein kann.
    Du benutzt einen typedef auf einen 'bekannten' Typen. In meinem Beispiel ist dieser inner Typ eine Struct, die nach meinem Ermessen nur ein mögliches Argument zulässt.

    Foo< int >::Inn i;
        std::cin >> i;
    

    an dieser Stelle habe ich keine Idee wie man eine Mehrdeutigkeit mit dieser - oder einer anderen - Template-Funktion konstruieren kann.

    template< typename T >
    std::istream& operator>>( std::istream& in, typename Foo< T >::Inn& i )
    

    Ich verstehe 14.8.2.4 so, dass grundsätzlcih alle diese Fälle ausgeschlossen sind, weil einige Konstruktionen dieser Art (wie Dein Beispiel) eben grundsätzlich mehrdeutig sein können.

    Gruß
    Werner



  • Werner Salomon schrieb:

    an dieser Stelle habe ich keine Idee wie man eine Mehrdeutigkeit mit dieser - oder einer anderen - Template-Funktion konstruieren kann.

    doch - tatsächlich 💡

    template< typename T >
    struct Foo {
        struct Inn {
            int m_x;
        };
        T m_y;
    };
    
    template<>
    struct Foo< bool > {
        typedef Foo< int >::Inn Inn;
    };
    

    eine geradezu gemeine Konstruktion; man muss nur lange genug drüber nachdenken, bis man's findet. 🕶

    Noch mal Danke Hume
    Gruß
    Werner



  • an dieser Stelle habe ich keine Idee wie man eine Mehrdeutigkeit mit dieser - oder einer anderen - Template-Funktion konstruieren kann.

    Z.B. so:

    struct Bar { typedef Foo<int>::In In };
    

    Nun hast du wieder eine Mehrdeutigkeit. Theoretisch könnte der Compiler diese natürlich erkennen und auflösen (Bar::In ist ja äquivalent zu Foo<int>::In). Nur dazu müsste der Compiler letztlich anfangen Typgleichungen zu lösen (bzw. alle Typen auf solche Mehrdeutigkeiten überprüfen). Was die Komplexität natürlich weiter in die Höhe schrauben würde (und die Compilezeit). Für solche Sachen eignet sich OCaml dann wohl doch besser 😉



  • Sorry, zwischen Gang zum Kühlschrank und Posten nicht aktualisert 😞


Anmelden zum Antworten