templates mit mehreren Rückgabe Typen


  • Mod

    Ist das nicht sowieso ein Fall für einen Variant-Container?



  • Nein, das ist ein klassischer Fall für verschiedene Funktionen. Das Template bringt hier nur Nachteile.



  • @XSpille danke das funktioniert

    template<typename T> class type_info{};
    
        static int get(type_info<int> t, const QString& name){
            Settings* setting = findSetting(name);
            return setting->data;
        }
    
        static void set(type_info<int> t, const QString& name, int value){
            Settings* setting = findSetting(name);
            setting->data = value;
        }
    
        static int get(type_info<bool> t, const QString& name){
            Settings* setting = findSetting(name);
            return setting->data == 0 ? false : true;
        }
    
        static void set(type_info<bool> t, const QString& name, bool value){
            Settings* setting = findSetting(name);
            setting->data = !value ? 0 : 1;
        }
    
        static QString get(type_info<QString> t, const QString& name){
            Settings* setting = findSetting(name);
            return setting->str_data;
        }
    
        static void set(type_info<QString> t, const QString& name, QString value){
            Settings* setting = findSetting(name);
            setting->str_data = value;
        }
    
        template<typename T>
        static T get(type_info<T> t, const QString& name){
            throw Exception("unsupported type of setting");
        }
    
        template<typename T>
        static void set(type_info<T> t, const QString& name, T value){
            throw Exception("unsupported type of setting");
        }
    
        template<typename T> static T get(const QString& name) {
            return get(type_info<T>(), name);
        }
    
        template<typename T> static void set(const QString& name, T value) {
            set(type_info<T>(), name, value);
        }
    


  • wxSkip schrieb:

    @XSpille: Was genau ist an deiner Lösung besser als an Spezialisierung? Machst du das, weil Spezialisierung angeblich "böse" ist?

    Liegt wahrscheinlich daran, dass ich template-Funktionen eigentlich nie spezialisiere. Ich poste dann PiCiJi mal, was du meintest:

    #include <string> 
    
    template<typename T> class type_info{}; 
    
    template<typename T> 
    static T get(type_info<T> t, const std::string& s){ 
        throw std::string("Oops"); 
    } 
    
    template<>
    int get<>(type_info<int> t, const std::string& s){ 
        return 0; 
    } 
    
    template<>
    std::string get<>(type_info<std::string> t, const std::string& s){ 
        return "string"; 
    } 
    
    template<typename T> static T get(const std::string& name) { 
        return get(type_info<T>(), name); 
    } 
    
    int main(){ 
        int i = get<int>(std::string("Hallo")); 
        std::string s = get<std::string>(std::string("Hallo")); 
        double d = get<double>(std::string("Hallo")); 
    }
    

    camper schrieb:

    Ist das nicht sowieso ein Fall für einen Variant-Container?

    Sehe ich absolut nicht so...

    cooky451 schrieb:

    Nein, das ist ein klassischer Fall für verschiedene Funktionen. Das Template bringt hier nur Nachteile.

    Wahrscheinlich hast du recht, aber in Template-Funktionen macht sowas schon manchmal Sinn...



  • cooky451 schrieb:

    Nein, das ist ein klassischer Fall für verschiedene Funktionen. Das Template bringt hier nur Nachteile.

    Außer, er will es aus einem anderen Template heraus benutzen.



  • Ich versteh nicht ganz was ein throw in dieser Funktion zu suchen hat, das ist ja kein runtime error. Ich würde hier einfach die Funktion spezialisieren (wie schon von anderen angemerkt):

    template< class T >
    T get( const std::string & )
    {
        static_assert( sizeof( T ) == 0 , "get< T > - unsupported Type" );
    }
    template<>
    int get< int >( const std::string & )
    {
        //...
    }
    template<>
    bool get< bool >( const std::string & )
    {
        //...
    }
    

    Warum Funktionstemplates nicht spezialisieren sollte hängt mit der overload resolution zu tun, und die spielt hier ja keine Rolle.



  • wxSkip schrieb:

    cooky451 schrieb:

    Nein, das ist ein klassischer Fall für verschiedene Funktionen. Das Template bringt hier nur Nachteile.

    Außer, er will es aus einem anderen Template heraus benutzen.

    Ok, dann ist eine Spezialisierung wie bei GorbGorb aber immer noch sinnvoller.

    (Außer dass ich nicht ganz verstehe, warum er nicht gleich static_assert(false, ..) schreibt. ;))


  • Mod

    struct Settings
    {
        std::string str_data;
        int data;
    };
    
    Settings* findSetting(const std::string&);
    
    template <typename T> struct type2member;
    template <> struct type2member<int>         : std::integral_constant<int Settings::*, &Settings::data> {};
    template <> struct type2member<bool>        : std::integral_constant<int Settings::*, &Settings::data> {};
    template <> struct type2member<std::string> : std::integral_constant<std::string Settings::*, &Settings::str_data> {};
    
    template <typename T>
    T get(const std::string& name)
    {
         return findSetting(name)->*type2member<T>::value;
    }
    
    template <typename T>
    void set(const std::string& name, const T& v)
    {
        findSetting(name)->*type2member<T>::value = v;
    }
    

    Solange nicht noch extra Umwandlungen im Spiel sind, wird hier nur eine Zuordnung Typ->Member benötigt.



  • cooky451 schrieb:

    (Außer dass ich nicht ganz verstehe, warum er nicht gleich static_assert(false, ..) schreibt. ;))

    Weil der static_assert dann auch ausgelöst wird, wenn man gar nichts instanziert.



  • type_info ist hier ja mal sowas von falsch...



  • 314159265358979 schrieb:

    type_info ist hier ja mal sowas von falsch...

    Qualitativ hochwertiger Kommentar 👍

    Es gibt Gründe, warum ich die Spezialisierung von Template-Funktionen meide...
    Wenn Experten, die fast so viel Ahnung von C++ haben wie du 🙄, davon abraten, dann nehm ich mir das zu Herzen: http://www.gotw.ca/publications/mill17.htm

    Also halt einfach die Fresse, solange keiner "Arsch öffne dich" sagt oder begründe deine Ansichten...



  • Weil du ein vollständig zur Kompilezeit bekanntes Problem zur Laufzeit erst löst. Sowas hätte selbst dir auffallen können, Schlaumeier.


  • Mod

    314159265358979 schrieb:

    type_info ist hier ja mal sowas von falsch...

    314159265358979 schrieb:

    Weil du ein vollständig zur Kompilezeit bekanntes Problem zur Laufzeit erst löst. Sowas hätte selbst dir auffallen können, Schlaumeier.

    Wobei das eine nichts mit dem anderen zu tun hat.



  • Blahblah, du weißt ganz genau wie's gemeint ist. Stell dich nicht dumm.



  • 314159265358979 schrieb:

    Weil du ein vollständig zur Kompilezeit bekanntes Problem zur Laufzeit erst löst. Sowas hätte selbst dir auffallen können, Schlaumeier.

    😕

    314159265358979 schrieb:

    Blahblah, du weißt ganz genau wie's gemeint ist. Stell dich nicht dumm.

    Ich jedenfalls stelle mich nicht dumm, sondern weiß wirklich nicht, wie es gemeint ist.

    Wieso wird die type_info zur Laufzeit ausgewertet? (Ernst gemeinte Frage...)

    Das assert statt Exception sehe ich absolut ein. Ich hab die Exception nur aus seinem Code übernommen ohne mir darüber Gedanken zu machen.
    Aber wenn man ein Vorgehen kritisiert und als Argument eine andere Sache nimmt, die nichts damit zu tun hat, dann stimmt irgendwas nicht.

    Ich bin eigentlich fest davon überzeugt, dass die type_info zur Kompilierzeit ausgewertet wird, lasse mich aber gerne eines Besseren belehren.

    Alles andere würde mich jedoch sehr wundern...



  • XSpille schrieb:

    Ich bin eigentlich fest davon überzeugt, dass die type_info zur Kompilierzeit ausgewertet wird, lasse mich aber gerne eines Besseren belehren.

    Der typeid -Operator ist Bestandteil von RTTI = Runtime Type Identification. Er wird schliesslich primär eingesetzt, um an den dynamischen Typen hinter Basisklassenverweisen zu kommen, welche per Definition erst zur Laufzeit feststehen.



  • Ach, ich sehe schon das Problem. Du hast deine Klasse dummerweise type_info genannt, worauf ich mir den Code nicht mehr genauer angesehen habe. Wer gibt seiner Klasse auch so einen Namen, wobei sie damit nicht mal ansatzweise was zu tun hat. Was du da verwendest, ist ein Type2Type von Alexandrescu, das passt schon so.


  • Mod

    Nexus schrieb:

    XSpille schrieb:

    Ich bin eigentlich fest davon überzeugt, dass die type_info zur Kompilierzeit ausgewertet wird, lasse mich aber gerne eines Besseren belehren.

    Der typeid -Operator ist Bestandteil von RTTI = Runtime Type Identification. Er wird schliesslich primär eingesetzt, um an den dynamischen Typen hinter Basisklassenverweisen zu kommen, welche per Definition erst zur Laufzeit feststehen.

    type_info != std::type_info
    Der Name mag etwas ungünstig gewählt sein für ein tag, mit RTTI hat es jedenfalls nichts zu tun.



  • Nexus schrieb:

    XSpille schrieb:

    Ich bin eigentlich fest davon überzeugt, dass die type_info zur Kompilierzeit ausgewertet wird, lasse mich aber gerne eines Besseren belehren.

    Der typeid -Operator ist Bestandteil von RTTI = Runtime Type Identification. Er wird schliesslich primär eingesetzt, um an den dynamischen Typen hinter Basisklassenverweisen zu kommen, welche per Definition erst zur Laufzeit feststehen.

    Hi Nexus,
    das weiß ich.

    @PI: Geht deine Kritik an die typeid oder an das typeinfo-Template, das ich gepostet habe?

    Ich dachte der Kommentar hatte sich auf das Template bezogen.

    EDIT: OK, alle Unklarheiten beseitigt. Dann gebe ich dir absolut recht.



  • 2


Anmelden zum Antworten