2009-11-03 11 views

Odpowiedz

50

Najbliższy rzeczą jest to, aby zadzwonić typeid(your_class).name() - ale to kompilator generuje specyficzny zniekształconej nazwy.

Aby go użyć klasa wewnątrz tylko typeid(*this).name()

+0

Dzięki .. to jest wystarczająco dobry do rejestrowania – mortal

+0

Trzeba wiedzieć, klasa pierwsza, aby wywołać tę ;-) –

+0

służy do logowania, więc wiem klasę gdzie jestem powołując się to. Po prostu staramy się unikać jednoznacznie definiując tablicę char zawierający nazwę klasy – mortal

9

Jeszcze nie. (Myślę, że gdzieś jest proponowane __class__). Możesz także spróbować wyodrębnić część klasową z __PRETTY_FUNCTION__.

3

Jeśli kompilator bywa g++ i prosicie __CLASS__, ponieważ chcesz uzyskać aktualną nazwę metody, w tym klasę, powinna pomóc __PRETTY_FUNCTION__ (zgodnie z info gcc, sekcja 5.43 Nazwy funkcji jako ciągi znaków).

55

Problem z używaniem typeid(*this).name() polega na tym, że w statycznym wywołaniu metody nie ma wskaźnika this. Makro __PRETTY_FUNCTION__ zgłasza nazwę klasy w funkcjach statycznych, a także wywołania metod. Będzie to jednak działać tylko z gcc.

Oto przykład wyodrębniania informacji za pomocą interfejsu w stylu makra.

inline std::string methodName(const std::string& prettyFunction) 
{ 
    size_t colons = prettyFunction.find("::"); 
    size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1; 
    size_t end = prettyFunction.rfind("(") - begin; 

    return prettyFunction.substr(begin,end) + "()"; 
} 

#define __METHOD_NAME__ methodName(__PRETTY_FUNCTION__) 

Makro __METHOD_NAME__ zwróci ciąg postaci <class>::<method>(), przycinanie zwracany typ, modyfikatory i argumenty z tego co __PRETTY_FUNCTION__ daje.

czegoś, co wydobywa tylko nazwę klasy, niektóre należy zwrócić uwagę na sytuacje pułapki, gdzie nie ma klasy:

inline std::string className(const std::string& prettyFunction) 
{ 
    size_t colons = prettyFunction.find("::"); 
    if (colons == std::string::npos) 
     return "::"; 
    size_t begin = prettyFunction.substr(0,colons).rfind(" ") + 1; 
    size_t end = colons - begin; 

    return prettyFunction.substr(begin,end); 
} 

#define __CLASS_NAME__ className(__PRETTY_FUNCTION__) 
+4

nie powinieneś otoczyć ten z '#ifdef __GNU_C__'? – einpoklum

+1

zamiast' substr (0, dwukropkami) .rfind (”„) '' można użyć rfind (””, dwukropek) 'oszczędzić tworem dodatkowy strunowy. – mariusm

+1

Wolałbym używać find_last_of ("::") W przeciwnym razie funkcja zwróci tylko przestrzeń nazw, jeśli istnieje jedna – underdoeg

4

myślę użyciu __PRETTY_FUNCTION__ jest wystarczająco dobry, choć zawiera nazw, jak również tj namespace::classname::functionname__CLASS__ jest dostępny.

1

Możesz uzyskać nazwę funkcji wraz z nazwą klasy. To może przetwarzać funkcje typu C.

static std::string methodName(const std::string& prettyFunction) 
{ 
    size_t begin,end; 
    end = prettyFunction.find("("); 
    begin = prettyFunction.substr(0,end).rfind(" ") + 1; 
    end -= begin; 
    return prettyFunction.substr(begin,end) + "()"; 
} 
1

Moje rozwiązanie:

std::string getClassName(const char* fullFuncName) 
{ 
    std::string fullFuncNameStr(fullFuncName); 
    size_t pos = fullFuncNameStr.find_last_of("::"); 
    if (pos == std::string::npos) 
    { 
     return ""; 
    } 
    return fullFuncNameStr.substr(0, pos-1); 
} 

#define __CLASS__ getClassName(__FUNCTION__) 

ja pracuje dla Visual C++ 12.

1

Oto rozwiązanie oparte na __FUNCTION__ szablonów makr i C++:

template <class T> 
class ClassName 
{ 
public: 
    static std::string Get() 
    { 
    // Get function name, which is "ClassName<class T>::Get" 
    // The template parameter 'T' is the class name we're looking for 
    std::string name = __FUNCTION__; 
    // Remove "ClassName<class " ("<class " is 7 characters long) 
    size_t pos = name.find_first_of('<'); 
    if (pos != std::string::npos) 
     name = name.substr(pos + 7); 
    // Remove ">::Get" 
    pos = name.find_last_of('>'); 
    if (pos != std::string::npos) 
     name = name.substr(0, pos); 
    return name; 
    } 
}; 

template <class T> 
std::string GetClassName(const T* _this = NULL) 
{ 
    return ClassName<T>::Get(); 
} 

Oto przykład jak to może być wykorzystane dla klasy rejestratora

template <class T> 
class Logger 
{ 
public: 
    void Log(int value) 
    { 
    std::cout << GetClassName<T>() << ": " << value << std::endl; 
    std::cout << GetClassName(this) << ": " << value << std::endl; 
    } 
}; 

class Example : protected Logger<Example> 
{ 
public: 
    void Run() 
    { 
    Log(0); 
    } 
} 

Wyjście Example::Run będzie wtedy

Example: 0 
Logger<Example>: 0 
+0

Pamiętaj, że nie uwzględnisz polimorfizmu, jeśli masz wskaźnik do bazy (co prawdopodobnie jest w porządku). –

0

To działa całkiem nieźle, jeśli jesteś gotów zapłacić koszt wskaźnika.

class State 
{ 
public: 
    State(const char* const stateName) :mStateName(stateName) {}; 
    const char* const GetName(void) { return mStateName; } 
private: 
    const char * const mStateName; 
}; 

class ClientStateConnected 
    : public State 
{ 
public: 
    ClientStateConnected(void) : State(__FUNCTION__) {}; 
}; 
7

chciałbym sugerować boost::typeindex, którą poznałem od Scotta Meyera "skutecznych, nowoczesnych C++" Oto prosty przykład:

Przykład

#include <boost/type_index.hpp> 

class foo_bar 
{ 
    int whatever; 
}; 

namespace bti = boost::typeindex; 

template <typename T> 
void from_type(T t) 
{ 
    std::cout << "\tT = " << bti::type_id_with_cvr<T>().pretty_name() << "\n"; 
} 

int main() 
{ 
    std::cout << "If you want to print a template type, that's easy.\n"; 
    from_type(1.0); 
    std::cout << "To get it from an object instance, just use decltype:\n"; 
    foo_bar fb; 
    std::cout << "\tfb's type is : " 
       << bti::type_id_with_cvr<decltype(fb)>().pretty_name() << "\n"; 
} 

Zestawione z „g ++ - -std = C++ 14" to produkuje następujące

Output

Jeśli chcesz wydrukować typ szablonu, to proste.

T = podwójny

Aby dostać od instancji obiektu, wystarczy użyć decltype: typ

FB jest: foo_bar

+0

Czy można w ten sposób uzyskać nazwę klasy bez przestrzeni nazw? aka http://coliru.stacked-crooked.com/a/cf1b1a865bb7ecc7 – tower120

0

Works z MSVC i GCC zbyt

#ifdef _MSC_VER 
#define __class_func__ __FUNCTION__ 
#endif 

#ifdef __GNUG__ 
#include <cxxabi.h> 
#include <execinfo.h> 
char *class_func(const char *c, const char *f) 
{ 
    int status; 
    static char buff[100]; 
    char *demangled = abi::__cxa_demangle(c, NULL, NULL, &status); 
    snprintf(buff, sizeof(buff), "%s::%s", demangled, f); 
    free(demangled); 
    return buff; 
} 
#define __class_func__ class_func(typeid(*this).name(), __func__) 
#endif 
0

następującej metody (na podstawie methodName) (powyżej) mogą również obsługiwać wejściowych, takich jak "int głównym (int ARGC char ** argv)":

string getMethodName(const string& prettyFunction) 
{ 
    size_t end = prettyFunction.find("(") - 1; 
    size_t begin = prettyFunction.substr(0, end).rfind(" ") + 1; 

    return prettyFunction.substr(begin, end - begin + 1) + "()"; 
}