template spezialisierung: unerwartetes ergebnis



  • #include <iostream>
    using namespace std;
    
    template<class T>
    struct IsConst
    {
        static const bool Result=false;
        typedef T Type;
    };
    
    template<class T>
    struct IsConst<const T>
    {
        static const bool Result=true;
        typedef T Type;
    };
    
    template<class T>
    struct IsConst<const T&>
    {
        static const bool Result=true;
        typedef T Type;
    };
    
    template<class T>
    struct IsConst<const T*>
    {
        static const bool Result=true;
        typedef T Type;
    };
    
    int main()
    {    
        cout << IsConst<int>::Result        <<endl;
        cout << IsConst<int*>::Result       <<endl;
        cout << IsConst<int&>::Result       <<endl;
        cout << IsConst<const int>::Result  <<endl;
        cout << IsConst<const int*>::Result <<endl;
        cout << IsConst<const int&>::Result <<endl; 
        cin.get();
    }
    

    Ausgabe (Dev-Cpp 4.9.9.0):
    0
    0
    1
    1
    1
    1



  • was noch interessant ist:

    //spezialisierung
    template<class T>
    struct IsConst<const T*>
    {
        static const bool Result=true;
        typedef T Type;
    };
    
    cout << IsConst<const int*>::Result<<endl;//findet er
    cout << IsConst<const int**>::Result<<endl;//findet er nicht
    

    aber:
    (andere Klasse)

    template<class T>
    struct IsPointer{
        static const bool Result=false;
    	typedef T Type;
    };
    template<class T>
    struct IsPointer<T*>{
        static const bool Result=true;
    	typedef typename IsPointer<T>::Type Type;
    };
    
    cout << IsPointer<int*>::Result<<endl;//findet er
    cout << IsPointer<int**>::Result<<endl;//findet er
    

    strange...



  • otze schrieb:

    was noch interessant ist:

    //spezialisierung
    template<class T>
    struct IsConst<const T*>
    {
        static const bool Result=true;
        typedef T Type;
    };
    

    Warum bitte definierst du das const T* als const wo der Typ eindeutig nicht const ist? Es handelt sich hier schließlich um einen normalen Pointer.

    aber wieso wählt der gcc an der stelle falsch aus?

    Ich würde das jetzt ehrlich gesagt für einen Compilerfehler halten, da eine Referenz nicht const sein kann.
    Code wie: int& const ist entwder illegal oder wird ignoriert, abhängig vom Kontext.

    Cv-qualified references are ill-formed except when
    the cv-qualifiers are introduced through the use of a typedef or of a
    template type argument, in which case cv-qualifiers are ignored.

    Insofern müsste sowohl IsConst<int&>, als auch IsConst<const int&> false liefern.



  • Warum bitte definierst du das const T* als const wo der Typ eindeutig nicht const ist? Es handelt sich hier schließlich um einen normalen Pointer.

    sorry, versteh ich nicht...

    nsofern müsste sowohl IsConst<int&>, als auch IsConst<const int&> false liefern.

    und das ist das problem. wenn ich zuerst auf const teste(welches nicht erkannt wird...), dann die referenz entferne, stehe ich mit const T da, und irgendwie wiederstrebt mir gedanke sowas zu haben, wenn ich doch den Typ ohne jeden schnörkel haben will. 😉



  • otze schrieb:

    Warum bitte definierst du das const T* als const wo der Typ eindeutig nicht const ist? Es handelt sich hier schließlich um einen normalen Pointer.

    sorry, versteh ich nicht...

    Was verstehst du nicht. const T* ist nicht top-level cv-qualifiziert. Der Typ ist "Zeiger auf const T" nicht "const-Zeitger auf irgendwas". Insofern ist die Antwort IsConst<const T*>::Result == ja, falsch. Oder zumindest sehr verwirrend, da alle mir bekannten IsConst-Helfer sich auf top-level-const konzentrieren.

    wenn ich zuerst auf const teste(welches nicht erkannt wird...), dann die referenz entferne, stehe ich mit const T da, und irgendwie wiederstrebt mir gedanke sowas zu haben, wenn ich doch den Typ ohne jeden schnörkel haben will.

    Warum machst du nicht einfach sowas wie
    remove_const<remove_reference<T>::type>::type?



  • zum ersten: ja, da ging ich von anderen prämissen aus, aber im nachhinein hast du sicher recht,ist logischer 🙂

    mein fehler war, dass ich mir das const so gedacht hab:
    const(T*)
    richtig ist aber (const T)*
    (die klammern sind nur zum kenntlich machen der zugehörigkeit)

    naja, wieder was gelernt 🙂

    lustig wirds aber bei so einem typ: const int* const& das T da rauszubekommen wird schwer^^



  • otze schrieb:

    lustig wirds aber bei so einem typ: const int* const& das T da rauszubekommen wird schwer^^

    Nicht wirklich. Schau dir z.B. einfach mal CompoundT aus "C++ Templates - The Complete Guide" von Josuttis und Vandevoorde an.
    Den Code findest du hier: http://www.josuttis.com/tmplbook/toc.html
    im Abschnitt "Type Classification".



  • da steht das nicht, da steht nur, wie man rausbekommen kann, ob ein Typ ein pointer/referenc etc ist.

    aber ich hab schon ne lösung 🙂

    template<class T>
    struct PureT{
        typedef T Type;
    };
    template<class T>
    struct PureT<const T>{
        typedef typename PureT<T>::Type Type;
    };
    template<class T>
    struct PureT<volatile T>{
        typedef typename PureT<T>::Type Type;
    };
    template<class T>
    struct PureT<T*>{
        typedef typename PureT<T>::Type Type;
    };
    template<class T>
    struct PureT<T&>{
        typedef typename PureT<T>::Type Type;
    };
    
    PureT<const int* const&>::Type a=5;
    


  • otze schrieb:

    da steht das nicht

    Also in meiner Ausgabe des Buches enthält CompoundT einen Typ namens BottomT, der den "ultimate nonpointer, nonreference and nonarray type on which T is built" liefert. Wendest du auf diesen noch remove_const an, dann hast du eigentlich genau das, was du willst, oder?



  • ahjo 🙂 stimmt. ist aber in etwa das,w as ich gemacht hab 🙂


Anmelden zum Antworten