template spezialisierung: unerwartetes ergebnis



  • also, ich hab eine ganz kleine Klasse zum testen eines types auf const geschrieben:

    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 typename T Type;
    };
    

    result steht dafür, ob der wert const ist oder nicht, und type stellt den Typ ohne Const da.

    nun hab ich zum testen ein kleines programm geschrieben:

    int main(){
    	std::cout<<IsConst<int>::Result<<std::endl;
    	std::cout<<IsConst<int*>::Result<<std::endl;
    	std::cout<<IsConst<int&>::Result<<std::endl;
    	std::cout<<IsConst<const int>::Result<<std::endl;
    	std::cout<<IsConst<const int*>::Result<<std::endl;
    	std::cout<<IsConst<const int&>::Result<<std::endl;
    }
    

    die ausgabe verwirt mich aber:
    0 0 1 1 0 1
    zum vergleich die erwartete ausgabe:
    0 0 0 1 1 1

    ich kam nicht dahinter, und hab dann die weiteren spezialisierungen für referenzen und zeiger geschrieben(nur mit T& bzw T* statt T), und dann gings.
    aber wieso wählt der gcc an der stelle falsch aus?
    wieso soll ein int& konstant sein?



  • Keine neuen Erkenntnisse, aber der icc liefert:

    0
    0
    0
    1
    0
    0



  • #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