type trait zum überprüfen ob Klassen Template vorliegt



  • Ich möchte überprüfen ob ein Type T ein Klassen template ist oder nicht.

    Mein Ansatz funktioniert leider nicht 100%:

    #include <iostream>
    #include <type_traits>
    #include <array>
    #include <vector>
    using namespace std;
    
    template<typename T>
    struct is_class_template : std::false_type { };
    
    template<template <typename...> class T, typename... Args>
    struct is_class_template<T<Args...>> : std::true_type { };
    
    struct foo {};
    
    int main() {
        std::cout << std::boolalpha;
        std::cout << is_class_template<bool>::value << std::endl; // false, correct
        std::cout << is_class_template<foo>::value << std::endl;  // false, correct
        std::cout << is_class_template<std::vector<int>>::value << std::endl; // true, correct
    
        std::cout << is_class_template<std::array<int, 2>>::value << std::endl; // false, NOT correct, why?
    
        return 0;
    }
    

    http://ideone.com/dBcHCC

    Warum funktioniert er nicht und gibt es eine funktionierendes type trait stattdessen?


  • Mod

    Ich möchte überprüfen ob ein Type T ein Klassen template ist oder nicht.

    Du möchtest prüfen ob ein Typ eine Spezialisierung eines Klassentemplates ist.

    Das ist mit aktuellen Mitteln nicht zu machen, denn das in deinem Beispiel aufgezeigte Problem lässt sich nicht umgehen. Ich habe eine Zeitlang an einem Paper für Alias Template Parameter gearbeitet, aber darauf würde EWG wahrscheinlich nicht positiv reagieren, von daher…

    Falls du das tatsächlich "benötigen" solltest, erzähl uns lieber vom Problem anstatt deines Lösungsversuchs.



  • Deine Erklärung ist für micht unzureichend.
    Warum funktioniert mein trait für std::vector<T>, selbst std::string klappt perfekt?

    Was ist so besonders an dem std::array<T,int>?

    Von welchem Problem redest du?


  • Mod

    Verstehst du überhaupt, was typename... tut? Und was ein Template-Parameter ist? Wenn ja, bedürft es keiner weiteren Erklärung, denn es gibt kein Äquivalent von typename... , das alle Arten von Template-Parametern abdeckt. Sonst recherchiere erstmal, was genau dein Code tut.



  • Nash26 schrieb:

    Was ist so besonders an dem std::array<T,int>?

    Das besondere an std::array ist, dass es non-type template Parameter hat. Diese kann man momentan wohl nicht mit einem Variadic Template erschlagen.



  • Nash26 schrieb:

    Von welchem Problem redest du?

    Du willst mit dem Template ja wohl irgendwas erreichen. Was? Welches Problem willst du hier lösen?



  • Jo, meine erste Frage wär auch: Was genau willst du mit der Information, dass es sich bei dem Type um eine Instanz eines Template handelt genau anfangen? Sowas klingt nämlich schwer danach, dass du dein eigentliches Problem grad völlig vekehrt rum angehst...



  • Genau. Siehe auch http://xyproblem.info/



  • sebi707 schrieb:

    Nash26 schrieb:

    Was ist so besonders an dem std::array<T,int>?

    Das besondere an std::array ist, dass es non-type template Parameter hat. Diese kann man momentan wohl nicht mit einem Variadic Template erschlagen.

    Das scheint hier wohl der Grund zu sein, das mischen von non-type und type Parametern.

    Ihr habt natürlich recht, das ist nicht das eigentliche Problem.
    Das eigentliche Problem ist, zu testen ob ich von einem Type den operator< verwenden kann oder nicht. Insbesondere wegen Klassen Templates, lässt sich das nicht überprüfen. Das template hat vielleicht den operator deklariert, aber ob er auch definiert ist (also der Template parameter den operator auch unterstützt)?



  • Und was soll passieren wenn der operator nicht unterstützt wird?


  • Mod

    Das kann man sich mittels SFINAE relativ einfach selber basteln. Gibt's auch in Boost schon fix und fertig, so dass man nicht einmal das tun muss. Komischerweise ist boost::has_less kein Teil der Standardbibliothek, obwohl vieles von Boost::type_traits in den Standard aufgenommen wurde. Mittels enable_if (sowohl in Boost als auch im C++11-Sprachstandard enthalten), kann man mit dem Ergebnis sogar etwas anfangen. Die Frage ist bloß: Was? Bei vielen anderen Traits (insbesondere die, deren Überprüfung in den Sprachstandard aufgenommen wurde; was wahrscheinlich genau der Grund dafür ist) kann ich mir ja vorstellen, dass man sinnvoll unterschiedliche Versionen des gleichen Codes anbieten kann. Aber bei einem Vergleich? Was für ein Algorithmus soll das denn sein, der Vergleiche benötigt, aber der zur Not auch ohne auskommt?

    Dir ist bekannt, dass es bereits jetzt einen Fehler beim Compilieren gibt, wenn du einen Code schreibst, der den Vergleichsoperator nutzt, aber kein Vergleichsoperator zur Verfügung steht? Ganz ohne irgendwelche Vorprüfungen durch den Programmierer. Egal ob in Templates oder außerhalb. Das klingt eher nach dem, was du möchtest. Oder kurz gesagt: Gar nichts zu tun scheint hier die richtige Lösung zu sein.



  • Wie inzwischen festgestellt, funktioniert es nicht. Auch boost kann es nicht:

    There is an issue when applying this trait to template classes. If operator< is defined but does not bind for a given template type, it is still detected by the trait which returns true instead of false. Example:

    http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/boost_typetraits/reference/has_less.html

    Deswegen ist es nicht im standard.

    Ich habe eine eigenes std::any entwickelt, das zusaetzlich vergleichs operationen ermoeglichen soll. Somit wird der vergleichsoperator beim zuweisen instanziert. Ob er nun gebraucht wird oder nicht.



  • Okay, da keine Rückmeldung kam, nehme ich an der Fall ist geklärt.

    Es gibt für beide Probleme keine Lösung mit C++, zumindest im jetzigen stand.


Log in to reply