Wie kann man überprüfen ob ein Type definiert ist?



  • Schönen Dank für die schnelle Antwort und in der Richtung hatte ich mir dies schon in etwa auch gedacht. Leider funktioniert bei mir der Quellcode nicht wirklich.

    Es wird immer zu false evaluiert und ich kann auch leider nicht erkennen, woran dies liegt. Ich verwende eine g++-4.3.2 und habe es auch auf einem g++-4.1.2 unter linux getestet. Ich denke aber, dass es nicht am compiler liegt.

    Grüße


  • Administrator

    Ach ich Trottle, der Code kann nicht funktionieren. Verändere die folgende Zeile, wie folgt:

    bool const DO_SELECT = CheckGW<StructWithGW, int>::RESULT;
    

    Jetzt wird DO_SELECT true sein. Allerdings ist es nicht das, was du willst. Zeigt dafür sehr schön meinen Denkfehler 🙂

    Aktuell fällt mir nix ein, wie man es denn nun machen könnte. Ich werde mir das nochmals durch den Kopf gehen lassen, vielleicht fällt mir noch was ein. Aber aktuell muss ich zur Post 😉

    Grüssli



  • Ja, genau. So hatte ich es auch hinbekommen, aber wie Du schon sagst ist es nicht ganz was ich brauchen würde. Aber trotzdem schon mal Danke. Wenn Dir oder jemand anderem noch was einfällt, wäre ich über weitere Hilfe dankbar.

    Grüße


  • Administrator

    Ok, also diese Lösung funktioniert auf dem MSVC2008:

    //////////////////////////////////////////////////////////////////////////
    // main : Implementation file
    
    #include <iostream>
    
    template<bool S, typename T1, typename T2>
    struct Select
    {
    	typedef T1 Result;
    };
    
    template<typename T1, typename T2>
    struct Select<false, T1, T2>
    {
    	typedef T2 Result;
    };
    
    struct StructWithGW
    {
    	typedef int gw;
    };
    
    template<int I>
    struct Int2Type
    {
    };
    
    template<typename T>
    struct Type2Type
    {
    };
    
    typedef char Small;
    class Big { char dummy[2]; };
    
    template<typename T>
    Small check_gw(Type2Type<typename T::gw> tt = Type2Type<typename T::gw>());
    
    template<typename T>
    Big check_gw(Type2Type<T> tt = Type2Type<T>());
    
    void foo(Int2Type<true>)
    {
    	std::cout << "true" << std::endl;
    }
    
    void foo(Int2Type<false>)
    {
    	std::cout << "false" << std::endl;
    }
    
    int main()
    {
    	bool const FIRST = sizeof(check_gw<int>()) == sizeof(Small);
    	bool const SECOND = sizeof(check_gw<StructWithGW>()) == sizeof(Small);
    
    	foo(Select
    		<
    			FIRST,
    			Int2Type<true>,
    			Int2Type<false>
    		>::Result());
    
    	foo(Select
    		<
    			SECOND,
    			Int2Type<true>,
    			Int2Type<false>
    		>::Result());
    
    	std::cin.get();
    
    	return 0;
    }
    

    Ich möchte jetzt aber keine Frage hören, wieso denn der Kompiler nun die richtige Funktion der beiden check_gw auswählt. Denn ich habe keine Ahnung oder höchsten so einen ganz kleinen Schimmer, aber ob dies dann wirklich auch dem Standard entspricht, weiss ich nicht.

    Grüssli



  • Sieht nach SFINAE aus.


  • Administrator

    hustbaer schrieb:

    Sieht nach SFINAE aus.

    Jo, das ist auch mein leichter Schimmer, bzw. noch mit der Kombination um den ambiguous Call zu verhindern, denn diese Funktion:

    template<typename T>
    Big check_gw(Type2Type<T> tt = Type2Type<T>());
    

    Sollte ja eigentlich für jeden Typen passen. Also auch für StructWithGW. Trotzdem wird die andere Funktion ausgewählt und kein Kompilerfehler im Sinne von "ambiguous Call" geworfen, da eigentlich beide check_gw passen würden. Deshalb bin ich grad ein wenig überrascht, dass es wirklich funktioniert 🙂

    Grüssli



  • Dravere schrieb:

    diese Funktion:

    template<typename T>
    Big check_gw(Type2Type<T> tt = Type2Type<T>());
    

    Sollte ja eigentlich für jeden Typen passen. Also auch für StructWithGW. Trotzdem wird die andere Funktion ausgewählt und kein Kompilerfehler im Sinne von "ambiguous Call" geworfen, da eigentlich beide check_gw passen würden. Deshalb bin ich grad ein wenig überrascht, dass es wirklich funktioniert 🙂

    Bei mir bricht der Compiler genau damit ab und sagt, es ist ein "ambiguous call".

    Da würde ich doch dann glatt mal behaupten, dass der g++ hier wohl dichter am Standard ist. Nur leider hilft mir dies nicht. 😞

    Ich will mal versuchen die Funktion in eine Struktur zu packen. Vielleicht hilft dies.

    Gruß


  • Administrator

    Schreib mal diese Funktion um...

    template<typename T>
    Big check_gw(Type2Type<T> tt = Type2Type<T>());
    

    ... zu:

    template<typename T>
    Big check_gw(...);
    

    Die Ellipse hat die niedrigste Priorität, um als Treffer in Frage zu kommen. Das könnte vielleicht den "ambiguous call" lösen.

    Übrigens, was willst du damit genau erreichen? Die Lösung ist ein wenig komplex, um damit was sinnvolles zu machen, habe ich zumindest das Gefühl 🙂
    Vielleicht könnte man dein Problem einfacher lösen, mit anderen Mitteln 😉

    Grüssli



  • Womit lernt man derartige Templateprogrammierung? Buch?





  • Dies mit der Ellipse hilft leider nicht.

    Was ich erreichen will? Also ich habe eine etwas komplexere Konfiguration in einer Klasse config zusammengefasst.

    etwas sowas:

    struct config {
       typedef xy<a,b,c>   nl;
       typedef yz<nl, ...> anl;
       typedef ab<anl, ... > gw;
    };
    

    in manchen Konfigurationen habe ich nun den Type gw und muss dann entsprechenden Code für die Initialisierung etc. generieren. Dazu habe vorgehabt eine Art Configurator mit Hilfe von Template Meta Programmierung zu schreiben und dann darüber den Code zu erzeugen.

    Soweit die grobe Idee dahinter.

    Gruß


  • Administrator

    Gibt zwei Möglichkeiten, welche du sehr viel leichter anwenden könntest:
    1. Gib deinem struct config eine statische konstante Variable, welche definiert, ob etwas ausgeführt werden soll oder nicht. Diese statische Variable, kannst du dann direkt in der Select Struktur verwenden.
    2. Führe ein ConfigTypeTraits ein. Dort kannst du dann zum Beispiel diese Variable per Standard auf false setzen. Und für alle Klassen, welche doch so ein typedef ... gw haben, spezialisierst du ConfigTypeTraits und setzt den Wert auf true .
    2.1 Oder du setzt, falls der typedef ... gw als nicht vorhanden angenommen werden soll, das gw auf auf einen speziellen Typen, den du danach raussuchst. Zum Beispiel einen NullType . So haben alle Klassen ein typedef ... gw , nur bei gewissen ist er ganz sicher typedef NullType gw . Diese Spezialfälle lassen sich ganz einfach ermitteln.

    @"Womit lernt man derartige Templateprogrammierung? Buch?"
    Wie drakon schon gesagt hat, ja über Bücher und über selber ausprobieren. Wenn man sich in den Grundlagen der Templates auskennt, dann kann ich Modern C++ Design wirklich nur wärmstens empfehlen. Was der Typ einem da präsentiert, ist der absolute Hammer. Das gibt einem einen ganz neuen Blickwinkel.

    Grüssli



  • Also hier eine Version die geht mit...

    g++ 4.3.0
    g++ 3.4.5 <-- DAS hat mich überrascht
    Comeau Online 4.3.10.1 (strict=on)
    MSVC 8
    MSVC 9

    ...:

    #include <iostream>
    
    template<bool S, typename T1, typename T2>
    struct Select
    {
    	typedef T1 Result;
    };
    
    template<typename T1, typename T2>
    struct Select<false, T1, T2>
    {
    	typedef T2 Result;
    };
    
    template<int I>
    struct Int2Type
    {
    };
    
    typedef char NoType;
    class YesType { NoType dummy[2]; };
    
    template<typename T>
    struct Type
    {
    };
    
    struct NoHelper
    {
    	NoType result;
    };
    
    template<typename T>
    struct YesHelper
    {
    	YesType result;
    };
    
    NoHelper check_gw(...)
    {
    	return NoHelper();
    }
    
    template <typename T>
    YesHelper<typename T::gw> check_gw(Type<T>)
    {
    	return YesHelper<typename T::gw>();
    }
    
    // --------------------------
    
    struct StructWithGW
    {
    	typedef int gw;
    };
    
    struct StructWithNoGW
    {
    	typedef int blubb;
    };
    
    void foo(Int2Type<true>)
    {
    	std::cout << "has GW" << std::endl;
    }
    
    void foo(Int2Type<false>)
    {
    	std::cout << "has no GW" << std::endl;
    }
    
    // --------------------------
    
    int main()
    {
    	bool const SEL_INT = sizeof(check_gw(Type<int>()).result) == sizeof(YesType);
    	bool const SEL_STRUCT_WITH_GW = sizeof(check_gw(Type<StructWithGW>()).result) == sizeof(YesType);
    	bool const SEL_STRUCT_WITH_NO_GW = sizeof(check_gw(Type<StructWithNoGW>()).result) == sizeof(YesType);
    
    	foo(Select
    		<
    		SEL_INT,
    		Int2Type<true>,
    		Int2Type<false>
    		>::Result());
    
    	foo(Select
    		<
    		SEL_STRUCT_WITH_GW,
    		Int2Type<true>,
    		Int2Type<false>
    		>::Result());
    
    	foo(Select
    		<
    		SEL_STRUCT_WITH_NO_GW,
    		Int2Type<true>,
    		Int2Type<false>
    		>::Result());
    
    	std::cin.get();
    
    	return 0;
    }
    

    MSVC 7.1 hab' ich nimmer drauf, und VC6 brauchen wir garnicht erst probieren (geht sicher nicht).



  • Es funktioniert und Danke euch allen.

    Grüße

    PS: Sorry, dass ich mich so lange nicht gemeldet habe, aber ich war eine Weile ohne Netz.


Anmelden zum Antworten