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.
-
Sowas hatten wir glaube ich schon mal.
-
Mit C++11 und constexpr wird das Boost.MPL-Zeugs dort hinfällig.