Есть ли макрос __CLASS__
в С++, который дает имя класса, похожее на макрос __FUNCTION__
, которое дает имя функции
Есть ли макрос __CLASS__ в С++?
Ответ 1
Самое близкое, что нужно вызвать typeid(your_class).name()
- но это создает специфическое имя для компилятора.
Чтобы использовать его внутри класса просто typeid(*this).name()
Ответ 2
Проблема с использованием typeid(*this).name()
заключается в отсутствии указателя this
в вызове статического метода. Макрос __PRETTY_FUNCTION__
сообщает имя класса в статических функциях, а также вызовы методов. Однако это будет работать только с gcc.
Вот пример извлечения информации через интерфейс стиля макроса.
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__)
Макрос __METHOD_NAME__
вернет строку формы <class>::<method>()
, обрезает возвращаемый тип, модификаторы и аргументы из того, что дает __PRETTY_FUNCTION__
.
Для чего-то, что извлекает только имя класса, необходимо позаботиться о том, чтобы избежать ситуаций, когда нет класса:
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__)
Ответ 3
Пока нет. (Я думаю, что __class__
предлагается где-то). Вы также можете попытаться извлечь часть класса из __PRETTY_FUNCTION__
.
Ответ 4
Я хотел бы предложить boost:: typeindex, о котором я узнал из Scott Meyer "Эффективный современный С++". Вот базовый пример:
Пример
#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 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 type is : "
<< bti::type_id_with_cvr<decltype(fb)>().pretty_name() << "\n";
}
Скомпилированный с "g++ --std = С++ 14", это вызывает следующие
Выход
Если вы хотите напечатать тип шаблона, это легко.
T = double
Чтобы получить его из экземпляра объекта, просто используйте decltype:
Тип fb: foo_bar
Ответ 5
Я думаю, что использование __PRETTY_FUNCTION__
достаточно хорошо, хотя оно включает пространство имен, а также i.e. namespace::classname::functionname
, пока не будет __CLASS__
.
Ответ 6
Если ваш компилятор оказывается g++
, и вы запрашиваете __CLASS__
, потому что вам нужен способ получить текущее имя метода, включая класс, __PRETTY_FUNCTION__
должен помочь (согласно info gcc
, раздел 5.43 Функция Имена как строки).
Ответ 7
Если вы говорите о MS С++ (вы должны указать, esp как __FUNCTION__
является нестандартным расширением), есть __FUNCDNAME__
и __FUNCSIG__
символов, которые вы могли бы проанализировать
Ответ 8
Вы можете получить имя функции, включая имя класса. Это может обрабатывать функции 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) + "()";
}
Ответ 9
Мое решение:
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__)
Я работаю для Visual С++ 12.
Ответ 10
Здесь решение на основе шаблонов __FUNCTION__
и С++:
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();
}
Вот пример того, как это можно использовать для класса logger
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);
}
}
Результат Example::Run
будет тогда
Example: 0
Logger<Example>: 0
Ответ 11
Это работает довольно хорошо, если вы готовы заплатить стоимость указателя.
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__ ) {};
};
Ответ 12
Работает с msvc и gcc тоже
#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
Ответ 13
Следующий метод (основанный на методеName() выше) также может обрабатывать ввод типа "int main (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) + "()";
}