[Gelöst] Probleme beim automatischen Erschließen des Template-Typen



  • Hallo,

    beim Lesen eines Papers von Stroustrup über C++0x habe ich mal ein wenig mit Constraints herumprobiert und sein Beispiel 'find_if' aufgegriffen. Dafür habe ich mir zwei Constraint-Klassen geschrieben, die u.a. auch testen sollen, ob 'Pred' (siehe Code) eine Funktion ist, die ein 'T' akzeptiert und ein 'bool' zurückgibt. Daher meine Funktion '_find_if':

    template <class T, class It, class Pred>
    It _find_if(It first, It last, Pred p)
    {
        Constraint_ForwardIterator<It, T>();
        Constraint_Predicate<Pred, T>();
        while (first != last && !p(*first)) ++first;
        return first;
    }
    

    (Der Code der Constraints ist für mein Problem unwichtig.)

    Leider kompiliert dieser Code nicht, VC++ 2005 moniert: "'It _find_if(It,It,Pred)' : could not deduce template argument for 'T'." Ist ja auch irgendwie logisch, denn 'T' wird nirgendwo verwendet. Also habe ich folgende Zeile eingefügt, um dem Compiler einen Hinweis zu geben, welchen Typ T hat:

    template <class T, class It, class Pred>
    It _find_if(It first, It last, Pred p)
    {
        Constraint_ForwardIterator<It, T>();
        Constraint_Predicate<Pred, T>();
        T x = *first; // *
        while (first != last && !p(*first)) ++first;
        return first;
    }
    

    Meiner Meinung nach müsste das jetzt funktionieren -- leider hat der Compiler eine andere Meinung und gibt den selben Fehler aus. Liegt das am Compiler oder ist es laut Standard tatsächlich nicht notwendig, dass der Compiler den Typ hier allein herausfindet? Im Prinzip müsste das doch gehen, indem der Compiler sich den Rückgabetyp von 'It::operator*()' (oder 'operator*(It)') anschaut, oder?



  • Tut er aber nicht. Der Compiler schaut sich um Template-Argumente herauszufinden nur die Parameter an. Du musst ihn also entweder explizit angeben oder du benutzt das typedef value_type aus den iterator_traits.

    /edit: also:

    template <class It, class Pred>
    It _find_if(It first, It last, Pred p)
    {
        typedef typename std::iterator_traits<It>::value_type T;
        Constraint_ForwardIterator<It, T>();
        Constraint_Predicate<Pred, T>();
        while (first != last && !p(*first)) ++first;
        return first;
    }
    


  • .filmor schrieb:

    Tut er aber nicht.

    Schade.

    Mit Iterator-Traits funktioniert es natürlich. Interessant ist aber, dass in VC 2005 die Fehlermeldung bei falschen Typen durch die Constraints nicht leserlicher wird -- was zum Großteil daran liegt, dass sie auch ohne Constraints schon sehr leserlich ist.

    EDIT: Danke natürlich für die Antwort.



  • Sind Constraints das gleiche wie Concept-Checking?



  • .filmor schrieb:

    Sind Constraints das gleiche wie Concept-Checking?

    Na ja, "das gleiche" ... Konzepte funktionieren in C++ zur Zeit ja noch nicht. Insofern sind die Constraints ein Workaround, das zur Compilezeit bestimmte Bedingungen für die Typen überprüft -- im Prinzip genauso wie ein Konzept. Ich vergleiche sowas immer am liebsten mit Typenklassen in Haskell, mit dem Unterschied, dass die Haskell-Typenklassen zusätzlich noch einen sehr mächtigen Mechanismus bereitstellen, der einem das Methodenschreiben abnimmt.

    Meine Constraints in dem Beispiel sehen aber im Prinzip genauso aus wie Stroustrups:

    template <class I, class T> struct Constraint_ForwardIterator {
        static void constraints(I a, T c) { ++a; a++; I b = a; b = a; *b = *a; c = *a; }
        Constraint_ForwardIterator() { void (*f)(I, T) = constraints; }
    };
    
    template <class P, class T> struct Constraint_Predicate {
        static void constraints(P p, T a) { bool x = p(a); }
        Constraint_Predicate() { void (*f)(P, T) = constraints; }
    };
    


  • Konrad Rudolph schrieb:

    Na ja, "das gleiche" ... Konzepte funktionieren in C++ zur Zeit ja noch nicht.

    Wohl ;), und zwar genauso, wie es bei C++ eigentlich immer gefordert wird: Nicht als Sprachfeature, sondern in Form einer Bibliothek.
    Ist wohl doch dasselbe wie Constraints, aber die Boost-Lib erspart einem einen Teil der Arbeit.



  • .filmor schrieb:

    Konrad Rudolph schrieb:

    Na ja, "das gleiche" ... Konzepte funktionieren in C++ zur Zeit ja noch nicht.

    Wohl ;), und zwar genauso, wie es bei C++ eigentlich immer gefordert wird: Nicht als Sprachfeature, sondern in Form einer Bibliothek.
    Ist wohl doch dasselbe wie Constraints, aber die Boost-Lib erspart einem einen Teil der Arbeit.

    Na ja, also in C++0x wird das doch die Form eines Sprachfeatures haben. Natürlich gibt es noch nichts genaues aber z.B. kursiert folgende Syntax (http://www.research.att.com/~bs/DnE2005.pdf):

    template <typename T> concept Predicate {
        Predicate p;
        T x;
        bool b = p(x);
    };
    
    // ...
    
    template <Container C, Predicate<C::value_type> Pred>
    bool all(C c, Pred p) {
        for(auto i = c.begin(); i != c.end(); ++i)
            if (!*i) return false;
        return true;
    }
    

    Neu ist hier natürlich des Schlüsselworts 'concept' und die Template-Deklaration mit eingebauter Überprüfung.

    Wobei ich persönlich (na, ich zähle ja nicht) diese Form der Überprüfung komisch finde. Ich fände es sozusagen als "abstrakte Basisklasse" logischer:

    template <typename T> concept Predicate {
        bool operator ()(T const&);
    };
    

    Natürlich ist der Begriff des Konzepts an sich nicht neu, SGI z.B. verwendet ihn durchgängig in seiner Dokumentation der STL-Implementierung.


Anmelden zum Antworten