__CLASS__ Makro?
-
Hi leute, ich brauche dringend ein makro, das mir den aktuellen klassen namen zurückgibt, typeid(*this).name() gibt leider immer "Class Klassennamen" zurück, und ein rumgesplitte wäre mir dann doch zu umständlich. Gibt es nicht so etwas wie __FUNCTION__ (also __CLASS__) in c++? Hab gegoogelt, aber nichts gefunden, und weder __class__ noch __CLASS__ scheinen definiert zu sein (zumindest nicht in MSVC++).
Kennt jemand das passende makro?
-
Zum Sprachstandard gehören die alle nicht. Das sind alles Zusatzfeatures bestimmter Compiler. Wenn dein Compiler dies nicht kennt, dann kannst du es auch nicht benutzen.
-
Gibt es nicht im C++ Standard.
Zudem ist der Rückgabewert vontypeid(*this).name()kompilerabhängig. Was da zurückkommt, darauf kannst du dich auch nicht verlassen. Gibt daher grundsätzlich keine vernünftige Methode, wie du zur Laufzeit an den Klassennamen kommst, ausser du speicherst ihn selbst.Grüssli
-
Nein, es gibt nichts Standardkonformes in dieser Richtung.
Klar, mit
typeid(*this).name()ist man auch nicht ganz portabel, aber besser als gar nichts. Und weshalb grosses Rumgesplitte?std::string a = "class Blub"; a.erase(0, sizeof("class"));
-
hm gibt dann die o.g. function wenigstens immer den Klassennamen richtig aus (wegen der Compilerabhänigkeit)?
-
Wo brauchst du das überhaupt? Je nachdem kann man sich auch eine standardkonforme, garantiert funktionierende Lösung ausdenken.
#define GET_CLASS_NAME(CLASS) \ static std::string GetClassName() \ { \ return #CLASS; \ } class MyClass { public: GET_CLASS_NAME(MyClass) };Zur Optimierung könnte man einen statischen
std::stringzwischenspeichern und eine Const-Referenz darauf zurückgeben. So spart man sich unnötige Konstruktionen und Kopien.
-
Krauzi schrieb:
hm gibt dann die o.g. function wenigstens immer den Klassennamen richtig aus (wegen der Compilerabhänigkeit)?
Was zurückkommt ist ziemlich undefiniert. Es steht nur, soweit ich mich erinnere, dass der Name "human readable" sein muss.
@Nexus,
Wozu überhaupt überstd::stringgehen? Lieber gleich ein Literal verwenden.#define CREATE_CLASS_NAME_GETTER(CLASS) \ static char const* get_class_name() \ { \ return #CLASS; \ }Falls man trotzdem ein
std::stringbraucht, geht die Konvertierung implizit.Grüssli
-
Dravere schrieb:
@Nexus,
Wozu überhaupt überstd::stringgehen?Gute Frage. Die Tatsache, dass ich gerade sonst noch mit
std::stringbeschäftigt war, hat meinen Horizont wohl zu stark eingeschränkt.
Allerdings hat meine Variante einen kleinen Vorteil: Sie ist effizienter, wenn man
GetClassName()alsconst std::string&speichert (z.B. häufig in Schnittstellen anzutreffen). Aberconst char*ist generischer, Performance dürfte hier wohl vernachlässigbar sein.
-
Nexus schrieb:
Dravere schrieb:
@Nexus,
Wozu überhaupt überstd::stringgehen?Gute Frage. Die Tatsache, dass ich gerade sonst noch mit
std::stringbeschäftigt war, hat meinen Horizont wohl zu stark eingeschränkt.
Allerdings hat meine Variante einen kleinen Vorteil: Sie ist effizienter bei Schnittstellen mit
const std::string&-Parametern, denen manGetClassName()übergibt.
Man könnte die Funktion ja noch entsprechend überladen

-
hmmmmmm schrieb:
Man könnte die Funktion ja noch entsprechend überladen

Nein, Überladung aufgrund unterschiedlicher Rückgabetypen funktioniert nicht, da letztere nicht zur Funktionssignatur gehören.
Man müsste zwei Funktionen mit verschiedenen Namen (oder Parametertypen, was aber weniger Sinn macht) anbieten.
-
Nexus schrieb:
Allerdings hat meine Variante einen kleinen Vorteil: Sie ist effizienter bei Schnittstellen mit
const std::string&-Parametern, denen manGetClassName()übergibt.
Daran zweifle ich etwas. Ich denke eher, dass beide Varianten gleich schnell sein werden, weil der Kompiler hier so extrem optimieren kann. Er kann die ganze Funktion verwerfen. Und ob er bei meiner Version dann wirklich einen
std::stringbaut, wenn dieser sowieso nur konstant ist, zweifelhaft. Wenn er wirklich gut ist, kann er diese Kopie auch gleich eliminieren und direkt das Literal als internen Puffer nehmen.Aber die Performance dürfte hier sowieso eher vernachlässigbar sein

Grüssli
-
Ich brauche das, weil ich gerade mit methoden pointern rumexperimentiere. Ich versuche gerade ein Interface für python objekte zu schreiben, dass automatisch alle freigegebenen attribute und methoden in entsprechende python funktionen umsetzt (also c++ instance -> python instance). Dafür wollte ich z.b. ein Makro definieren, dass nach diesem Format arbeitet:
#define METHOD(r,o,m) (r (o::*)() )(&o::m)
r = return value
o = klasse
m = methodeich dachte mir, dass ich vllt. das o weglassen könne, wenn man das mit einem __class__ ersetzten könnte, aber so ein makro gibts leider nicht, also hat sich das ganze erledigt.
Allerdings könnte mir wegen dem Methoden pointern gleich jemand helfen :P.
Ich hab jetzt schon viel gesucht, aber ich komme nicht zu einer vernünftigen lösung:
ich brauche eine methode, (von einer template klasse), die alle methoden abspeichern kann.
Dazu dachte ich an sowas.
[cpp]
template<class Class>
class MeineKlasse
{
....
template<typename Type> RegisterMethod( Type *methodenPointer ) {...}
[cpp]
das problem ist allerdings, dass ich nicht wirklich auf eine vernünftige lösung komme!
ich dachte, eine einfügen im plublic bereich mit den methoden pointer als typedef hiermit:
typedef string ( Class::*stringNoArg )( );
würde für eine simple methode wie string GetName() { return this->m_Name; } reichen. Hab mich wohl geteuscht.
Weis jemand, wie das gut und übersichtlich zu lösen wäre?
-
Krauzi schrieb:
... die alle methoden abspeichern kann.
Unmöglich, da die Funktionen jeweils einen anderen Typ haben. Man kann gewisse gleiche Arten von Funktionen speichern, aber das ist auch schon alles. Du müsstest also dieses "alle" genauer spezifizieren. Dann kannst du vielleicht etwas mit
boost::functionmachen.Grüssli
-
ich möchte nur ganz bestimmte funktionen registrieren können.
z.b. welche die kein argument benötigen und einen string zurückgeben.
Wie könnte ich zumindest diese funktion registrieren?
-
Dravere schrieb:
Aber die Performance dürfte hier sowieso eher vernachlässigbar sein

Ja, habe ich ja auch noch geschrieben (2. Edit).

Krauzi schrieb:
ich brauche eine methode, (von einer template klasse), die alle methoden abspeichern kann.
[...]
Weis jemand, wie das gut und übersichtlich zu lösen wäre?Du kannst unterschiedliche statische Typen nicht in einem einzelnen Container speichern (Typlisten sind hier ungeeignet). Also baust du dir mittels Type Erasure und dynamischer Polymorphie eine Abstraktion, mit der du Methoden einheitlich ansprechen kannst.
Zum Beispiel sowas:
// Abstrakte Basisklasse zur Speicherung von Methoden class AbstractMethod { public: virtual ~AbstractMethod() {} virtual const char* GetName() const = 0; }; // Konkrete Implementierung einer Methode template <typename MemFnPtr> class ConcreteMethod : public AbstractMethod { public: ConcreteMethod(const char* name, MemFnPtr pointer) : myName(name) , myPointer(pointer) { } virtual const char* GetName() const { return myName; } private: const char* myName; MemFnPtr myPointer; }; // Factory-Funktion (Vorsicht, gibt besitzenden Zeiger zurück) template <typename MemFnPtr> ConcreteMethod<MemFnPtr>* CreateConcreteMethod(const char* name, MemFnPtr pointer) { return new ConcreteMethod<MemFnPtr>(name, pointer); } // Makro zur handlichen Bearbeitung #define CREATE_CONCRETE_METHOD(METHOD) CreateConcreteMethod(#METHOD, &METHOD) // Test-Klasse struct MyClass { void Test(int) {} bool Test2() { return true; } }; // Anwendung #include <iostream> int main() { AbstractMethod* a = CREATE_CONCRETE_METHOD(MyClass::Test); AbstractMethod* b = CREATE_CONCRETE_METHOD(MyClass::Test2); std::cout << a->GetName() << std::endl; std::cout << b->GetName() << std::endl; delete a; delete b; }Und jetzt noch einen Container verwenden. Ideal wäre Boost.PtrContainer, da der den Speicher selbst freigibt. Ansonsten musst du eben manuell
deleten. Was die eigentlichen Memberfunktionszeiger betrifft, da weiss ich zu wenig über dein Design, aber du kannst dir ja eine entsprechende Schnittstelle überlegen.
-
#include <map> #include <string> #include <iostream> typedef std::string (*StrFunc) (); typedef std::map<std::string, StrFunc> FuncMap; class FunctionManager { private: FuncMap myMap; public: void add(const std::string& str, StrFunc func) { myMap.insert(std::make_pair(str, func)); } std::string call(const std::string& str) const { FuncMap::const_iterator it = myMap.find(str); if (it != myMap.end()) { return it->second(); } return "<Error>"; } }; std::string test() { return "test"; } int main() { FunctionManager manager; manager.add("lol", test); std::cout << manager.call("lol"); std::cin.get(); return 0; }