C + + 中有__ CLASS__ 宏吗?

在 C + + 中是否有一个 __CLASS__宏,它给出类名,类似于给出函数名的 __FUNCTION__

117120 次浏览

最接近的方法是调用 typeid(your_class).name()-但这会产生特定于编译器的错误名称。

在类中使用它只需 typeid(*this).name()

还没有。(我认为某处提出了 __class__)。您也可以尝试从 __PRETTY_FUNCTION__中提取类部分。

如果你正在谈论 MS C + + (你应该声明,尤其是因为 __FUNCTION__是一个非标准的扩展) ,有 ABC1和 __FUNCSIG__符号,你可以解析

如果您的编译器碰巧是 g++,并且您要求使用 __CLASS__,因为您想要一种方法来获得包括类在内的当前方法名称,那么 __PRETTY_FUNCTION__应该会有所帮助(根据 info gcc5.43函数名作为字符串部分)。

使用 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__)

我认为使用 __PRETTY_FUNCTION__已经足够好了,尽管它还包括名称空间,例如 namespace::classname::functionname,直到 __CLASS__可用。

可以获得包含类名的函数名。 这可以处理 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

如果您愿意支付指针的成本,那么这种方法将非常有效。

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

我想推荐 Typeindex,这是我从 Scott Meyer 的“有效的现代 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 = 双倍

要从一个对象实例获取它,只需使用 decltype:

Fb 的类型是: foo _ bar

也和 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) + "()";
}

如果需要在编译时生成类名,可以使用 C + + 11:

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


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

我知道这和 __FUNCTION__不是一回事,但是我在寻找这样一个答案的时候发现了这篇文章。校对: D

上面提到的所有依赖于 __PRETTY_FUNCTION__的解决方案都有特定的边缘情况,即它们不仅返回类名/类名。例如,考虑以下漂亮的函数值:

static std::string PrettyFunctionHelper::Test::testMacro(std::string)

使用最后一次出现的 "::"作为分隔符将不起作用,因为函数参数也包含 "::"(std::string)。 您可以找到类似的 "("边缘情况作为分隔符和更多。 我找到的唯一解决方案是同时使用 __FUNCTION____PRETTY_FUNCTION__宏作为参数:

namespace PrettyFunctionHelper{
static constexpr const auto UNKNOWN_CLASS_NAME="UnknownClassName";
/**
* @param prettyFunction as obtained by the macro __PRETTY_FUNCTION__
* @return a string containing the class name at the end, optionally prefixed by the namespace(s).
* Example return values: "MyNamespace1::MyNamespace2::MyClassName","MyNamespace1::MyClassName" "MyClassName"
*/
static std::string namespaceAndClassName(const std::string& function,const std::string& prettyFunction){
//AndroidLogger(ANDROID_LOG_DEBUG,"NoT")<<prettyFunction;
// Here I assume that the 'function name' does not appear multiple times. The opposite is highly unlikely
const size_t len1=prettyFunction.find(function);
if(len1 == std::string::npos)return UNKNOWN_CLASS_NAME;
// The substring of len-2 contains the function return type and the "namespaceAndClass" area
const std::string returnTypeAndNamespaceAndClassName=prettyFunction.substr(0,len1-2);
// find the last empty space in the substring. The values until the first empty space are the function return type
// for example "void ","std::optional<std::string> ", "static std::string "
// See how the 3rd example return type also contains a " ".
// However, it is guaranteed that the area NamespaceAndClassName does not contain an empty space
const size_t begin1 = returnTypeAndNamespaceAndClassName.rfind(" ");
if(begin1 == std::string::npos)return UNKNOWN_CLASS_NAME;
const std::string namespaceAndClassName=returnTypeAndNamespaceAndClassName.substr(begin1+1);
return namespaceAndClassName;
}
/**
* @param namespaceAndClassName value obtained by namespaceAndClassName()
* @return the class name only (without namespace prefix if existing)
*/
static std::string className(const std::string& namespaceAndClassName){
const size_t end=namespaceAndClassName.rfind("::");
if(end!=std::string::npos){
return namespaceAndClassName.substr(end+2);
}
return namespaceAndClassName;
}
class Test{
public:
static std::string testMacro(std::string exampleParam=""){
const auto namespaceAndClassName=PrettyFunctionHelper::namespaceAndClassName(__FUNCTION__,__PRETTY_FUNCTION__);
//AndroidLogger(ANDROID_LOG_DEBUG,"NoT2")<<namespaceAndClassName;
assert(namespaceAndClassName.compare("PrettyFunctionHelper::Test") == 0);
const auto className=PrettyFunctionHelper::className(namespaceAndClassName);
//AndroidLogger(ANDROID_LOG_DEBUG,"NoT2")<<className;
assert(className.compare("Test") == 0);
return "";
}
};
}
#ifndef __CLASS_NAME__
#define __CLASS_NAME__ PrettyFunctionHelper::namespaceAndClassName(__FUNCTION__,__PRETTY_FUNCTION__)
#endif

我用 C + + 17 constexpr std::string_view方法使用 __PRETTY_FUNCTION__constexpr创建了一个函数。我还更新了算法一点,以更可靠的 (感谢你在这篇文章中提供的帮助)。

constexpr std::string_view method_name(const char* s)
{
std::string_view prettyFunction(s);
size_t bracket = prettyFunction.rfind("(");
size_t space = prettyFunction.rfind(" ", bracket) + 1;
return prettyFunction.substr(space, bracket-space);
}
#define __METHOD_NAME__ method_name(__PRETTY_FUNCTION__)

在 C + + 20中,可以将函数声明为 consteval,强制它在编译时求值。