template typ als string



  • Was genau soll da zurückkommen?

    eigentlich genau das, was man als T angibt.

    Wie wärs mit sowas:

    gut, nach dem schema wäre es als spezialisierte template funktion weniger schreibarbeit:

    template<typename T> const char* toString(){ return "unknown";}
    
    template<> const char* toString<int>(){ return "int";}
    template<> const char* toString<double>(){ return "double";}
    
    // [...]
      std::cout << "with Type '"<< toString<T>() <<"'";
    

    arbeit ist es trotzdem und man muss es manuell erweitern.



  • typeid(T).name()



  • danke, ich glaube, das habe ich gesucht.



  • Es ist nicht definiert was typeid(bla).name() genau liefert, das ist völlig compilerabhängig...genau darum eben die Lösung über trait-artige templates.
    Die Version mit structs hat den Vorteil, dass du sie partiell spezialisieren kannst, z.B. um Pointertypen rekursiv zu behandeln. Zugegeben, mit const char* wird das wohl nicht so einach gehen, aber z.B. mit std::string schon...



  • Ich würde es wie dot vorgeschlagen machen. Mit ein paar Makros gewürzt wird das ganze dann auch besser lesbar.

    #include <iostream>
    #include <string>
    
    template <typename T>
    struct type_to_string;
    
    #define DEFINE_STRING_IMPL(pattern, val, ...) \
    	template <__VA_ARGS__> \
    	struct type_to_string<pattern> \
    	{ \
    		static std::string value() \
    		{ \
    			return val; \
    		} \
    	};
    
    #define TO_STRING(type) type_to_string<type>::value()
    
    #define DEFINE_STRING_0(pattern, value) DEFINE_STRING_IMPL(pattern, value)
    #define DEFINE_STRING_1(pattern, value) DEFINE_STRING_IMPL(pattern, value, typename T)
    #define DEFINE_STRING_2(pattern, value) DEFINE_STRING_IMPL(pattern, value, typename T, typename U)
    
    DEFINE_STRING_0(int   , "int")
    DEFINE_STRING_1(T*    , TO_STRING(T) + "*")
    DEFINE_STRING_2(T U::*, TO_STRING(T) + " " + TO_STRING(U) + "::*")
    
    struct foo {};
    
    DEFINE_STRING_0(foo, "foo")
    
    int main()
    {
    	std::cout << TO_STRING(int foo::**);
    }
    

    Wenn ein Typ nicht bekannt sein sollte, gibts einen Compilezeit-Fehler.



  • dot schrieb:

    Es ist nicht definiert was typeid(bla).name() genau liefert, das ist völlig compilerabhängig...

    Richtig.

    genau darum eben die Lösung über trait-artige templates.

    Naja, kommt drauf an was man braucht. Für Dinge wie Log-Ausgaben ist typeid(bla).name() oft vollkommen ausreichend.

    Die Version mit structs hat den Vorteil, dass du sie partiell spezialisieren kannst, z.B. um Pointertypen rekursiv zu behandeln. Zugegeben, mit const char* wird das wohl nicht so einach gehen, aber z.B. mit std::string schon...

    Oder auch indem man die C++ String-Builder Klasse verwendet, auch bekannt als std::vector<char> (allerdings dann als in/out Parameter, und nicht als Returnwert).



  • hustbaer schrieb:

    dot schrieb:

    Es ist nicht definiert was typeid(bla).name() genau liefert, das ist völlig compilerabhängig...

    Richtig.

    genau darum eben die Lösung über trait-artige templates.

    Naja, kommt drauf an was man braucht. Für Dinge wie Log-Ausgaben ist typeid(bla).name() oft vollkommen ausreichend.

    Absolut, ich ging natürlich ursprünglich davon aus, dass es eben um die konsistente Ausgabe ging, da ja sonst typeid() verwendet würde 😉

    hustbaer schrieb:

    Die Version mit structs hat den Vorteil, dass du sie partiell spezialisieren kannst, z.B. um Pointertypen rekursiv zu behandeln. Zugegeben, mit const char* wird das wohl nicht so einach gehen, aber z.B. mit std::string schon...

    Oder auch indem man die C++ String-Builder Klasse verwendet, auch bekannt als std::vector<char> (allerdings dann als in/out Parameter, und nicht als Returnwert).

    Stimmt, das wär vermutlich die bessere Lösung als der Rückgabewert, egal ob jetzt mit vector oder string.



  • also zu typeid(Type).name():
    In der jeweiligen Doku des Compilers sollte das durchaus spezifiziert sein 😉

    MSVC gibt da wunderbare brauchbare Strings zurück ala "int", "class foo" usw.
    GCC ist da etwas umständlicher, die nehmen Kürzel wie "i", "Ss" (S = std, s = string) usw. (kann man durch Probieren auch herausfinden)

    Also prinzipiell lässt sich damit Compiler-abhängig auch was bauen.


  • Mod

    Sowas hatten wir glaube ich schon mal.



  • Mit C++11 und constexpr wird das Boost.MPL-Zeugs dort hinfällig.


Anmelden zum Antworten