Есть ли макрос класса В C++?


есть __CLASS__ макрос в C++, который дает имя класса, похожее на __FUNCTION__ макрос, который дает имя функции

14 76

14 ответов:

самое близкое, что есть-назвать typeid(your_class).name() - но это создает компилятор конкретного искаженного имени.

использовать его внутри класса просто typeid(*this).name()

проблема с использованием 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>(), обрезка возвращаемого типа, модификаторов и аргументов из what __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__)

пока нет. (Я думаю __class__ предлагается где-то). Вы также можете попробовать извлечь часть класса из __PRETTY_FUNCTION__.

Я хотел бы предложить boost:: typeindex, о котором я узнал из "эффективного современного C++" Скотта Мейера вот основной пример:

пример

#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";
}

скомпилированный с "g++ -- std=c++14" это производит следующее

выход

Если вы хотите напечатать тип шаблона, это легко.

T = double

чтобы получить его из экземпляра объекта, просто использовать decltype:

тип fb: foo_bar

Я думаю, что с помощью __PRETTY_FUNCTION__ достаточно хорошо, хотя он также включает пространство имен, т. е. namespace::classname::functionname до __CLASS__ доступно.

если ваш компилятор бывает g++ а ты просишь __CLASS__ потому что вы хотите способ получить текущее имя метода, включая класс,__PRETTY_FUNCTION__ должно помочь (по данным info gcc, раздел 5.43 имена функций в виде строк).

Если вы говорите MS C++ (вы должны заявить, esp как __FUNCTION__ это нестандартное расширение), есть __FUNCDNAME__ и __FUNCSIG__ символы который вы могли разобрать

вы можете получить имя функции, включая имя класса. Это может обрабатывать функции 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) + "()";
}

мое решение:

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 C++ 12.

вот решение, основанное на __FUNCTION__ макро и 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();
}

вот пример того, как это может быть использовано для класса регистратора

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

Если вам нужно что-то, что будет фактически производить имя класса во время компиляции, вы можете использовать C++11 для этого:

#define __CLASS__ std::remove_reference<decltype(classMacroImpl(this))>::type

template<class T> T& classMacroImpl(const T* t);

Я признаю, что это не то же самое как __FUNCTION__ но я нашел этот пост, ища такой ответ. : D

это работает довольно хорошо, если вы готовы оплатить стоимость указатель.

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__ ) {};
};

работает с 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

следующий метод (основанный на methodName() выше) также может обрабатывать входные данные, такие как"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) + "()";
}