typeid,如何仅获取类型名称

typeid, how to get just type name only

示例代码:

    MainWindow::MainWindow(QWidget *parent) {
        QString strTemp = typeid(this).name();
        qDebug() << strTemp;
    }

我只想获取 class 名称,在上面的示例中我只是在 "MainWindow" 之后,我得到的是:

    class MainWindow *

当然,我可以编写一个例程来获取此字符串,然后去除 class 和指针部分,仅隔离 class 名称。有没有什么已经做到了?

在没有任何标准套路的情况下,我是这样做的:

        QString strTemp = typeid(this).name();
        qDebug() << strTemp;
        QStringList lstParts = strTemp.split(" ");

        if ( lstParts.length > 1 ) {
            strTemp = lstParts[1];
        }
        qDebug() << strTemp;

以上结果只有类型名称。最后我只需要 __FUNCTION__ 给出了 class 名称和调用它的方法将给出:

    MainWindow::MainWindow

cppreference 说了以下关于 std::type_info::name() 的内容:

Returns an implementation defined null-terminated character string containing the name of the type. No guarantees are given; in particular, the returned string can be identical for several types and change between invocations of the same program.

所以你在一个编译器下得到 class MainWindow 作为输出的事实并不意味着你会在不同的编译器(甚至是相同的编译器但更新的版本)下得到相同的输出。

为什么不使用 boost::typeindex::type_id_with_cvr 并使用一些类型特征,例如 remove_pointer_t 以获得所需的结果?

#include <iostream>
#include <sstream>
#include <string>
#include <boost/type_index.hpp>

class MainWindow {
public:
    void test()
    {
        std::ostringstream os;
        os << 
         boost::typeindex::type_id_with_cvr<std::remove_pointer_t<decltype(this)>>().pretty_name() 
          ;

        std::string s = os.str(); // easy transform to QString
        std::cout << s << std::endl;
    }
};

int main()
{
    MainWindow{}.test(); // as output MainWindow
    return 0;
}

Full demo

std::type_info::name() 不适合这种任务。正如 所指出的,此函数的 return 值是实现定义的,因此无法将其分解为类型名称,因为它以可移植的方式出现在源代码中。

在这种情况下,更好的方法是推出您自己的反射机制,这将使您能够完全控制类型字符串。不幸的是,该语言目前并没有为此提供很多支持,因此由此产生的机制有点像 hack。例如,您可以这样做:

#define ENABLE_REFLECTION_TYPE_NAME(class_name)                 \
inline constexpr char const* type_name(class_name const&) {     \
    return #class_name;                                         \
}

class Foo {};

ENABLE_REFLECTION_TYPE_NAME(Foo)
ENABLE_REFLECTION_TYPE_NAME(MainWindow)

MainWindow::MainWindow(QWidget *parent) {
    QString strTemp = type_name(*this);
    qDebug() << strTemp;             // prints "MainWindow"

    Foo f;
    QString strTemp2 = type_name(f);
    qDebug() << strTemp2;            // prints "Foo"
}

你真的不应该依赖 std::typeid,也不应该依赖 boost 或任何其他 C++-only-library。 None 其中保证您将在不同的编译器上获得类型名,尤其是对于损坏的类型。使用虚函数甚至 RTTI 都会影响类型的名称。没有什么能阻止您的编译器将 "MainWindow" 重命名为 "CellarDoor"。到目前为止,唯一的方法是使用某种反射(它(还)不是 C++ 的一部分)或一些预处理器。 ComicSansMS 提供了一个很好的 ,您可以在其中滚动自己的简单反射实现。

但是,由于您使用的是 QT,因此可以使用 QT Metaobjects for this. It actually has a method dedicated for this exact purpose; className

QMetaObject::className() returns the class name as a string at run-time, without requiring native run-time type information (RTTI) support through the C++ compiler.

只需调用 metaObject()->className():

MainWindow::MainWindow(QWidget *parent) {
    qDebug() << metaObject()->className();
}

moc 在任何编译器之前运行,并将 class 名称烘焙到代码中。查看 moc 生成的代码,您会看到如下内容:

static const qt_meta_stringdata_MainWindow_t qt_meta_stringdata_MainWindow = {
    {
QT_MOC_LITERAL(0, 0, 10), // "MainWindow"
QT_MOC_LITERAL(1, 11, 13), // "buttonClicked"
QT_MOC_LITERAL(2, 25, 0) // ""

    },
    "MainWindow[=11=]buttonClicked[=11=]"
};