C++中是否有__CLASS__宏?

138

C++ 中是否有类似于 __FUNCTION__ 宏用于获取函数名的 __CLASS__ 宏,以获取类名?

16个回答

94

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

7
你应该将这段代码用#ifdef __GNU_C__包围起来吗? - einpoklum
1
可以使用 rfind(' ', colons) 来避免创建额外的字符串,而不是 substr(0,colons).rfind(" ") - mariusm
2
我宁愿使用find_last_of("::"),否则该函数只会返回命名空间(如果有的话)。 - underdoeg
我编写了一个可能具有更广泛范围的 __METHOD_NAME__ 宏的版本。请查看这里 - Antonio
在C++11中,您可以尝试将此函数定义为“constexpr”函数,以便在编译时进行评估。 - Andre Holzner
显示剩余2条评论

76

最接近的称呼是调用 typeid(你的类).name() - 但它会生成特定于编译器的名称混淆。

若要在类内使用,请使用 typeid(*this).name()


2
typeid(*this).name() 可以在类函数内部使用。 - Aleksei Potov
2
这样比较好。至于了解类,定义字符数组比将其推迟到运行时更好。 - Michael Krelin - hacker
6
很遗憾它没有像__CLASS__一样被定义,这在预处理阶段会很方便!:( - k3a
2
@Max 它目前还不行,但是可能会有这个功能。就像它知道函数一样 :-P - k3a
6
@kexik:预处理器也不知道函数,标准的__func__和非标准的__FUNCTION__都不是宏。微软将__FUNCTION__文档化为宏,但它不是真正的宏的明显特征是,在使用/P编译时,它不会被预处理器展开。 - Steve Jessop
显示剩余3条评论

12

目前还没有。(我认为在某个地方提出了__class__)。您也可以尝试从 __PRETTY_FUNCTION__ 中提取类部分。


11
我想建议使用boost::typeindex,这是我从Scott Meyer的“Effective Modern 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

使用这个方法是否可以只获取类名而不包含命名空间?例如:http://coliru.stacked-crooked.com/a/cf1b1a865bb7ecc7 - tower120

8

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


7

如果您需要在编译时实际生成类名,可以使用C++11来完成此操作:

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

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

我知道这不是__FUNCTION__的同义词,但我在寻找这样的答案时发现了这篇帖子。:D


这是我迄今为止见过的最好的解决方案!它需要在编译时而不是运行时实现! - jaques-sam
编译错误,我尝试在GCC-11上使用选项-std=gnu++20。 - bzhu
7
它只获取类的类型,而不是字符串表示。 - bzhu

6

我使用C++17 constexprstd::string_view方法创建了一个函数,其中包含__PRETTY_FUNCTION__。我还稍微更新了算法以使其更可靠。(感谢@n. 'pronouns' m64387023中的帮助)。

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,强制它在编译时评估。此外,还有std::basic_fixed_string用作模板参数


这是最好的答案,在编译时得到你想要的。 - bzhu

4

如果你的编译器是 g++,并且你想要一种获取当前方法名(包括类名)的方式,那么使用 __PRETTY_FUNCTION__ 应该会有帮助(根据 info gcc 的第 5.43节 函数名作为字符串)。


3
您可以获取包括类名在内的函数名称。 这可以处理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) + "()";
}

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接