如何检查 C++ typeid(T) 调用是编译时还是运行时确定的?

Imm*_*ant 1 c++ virtual runtime compilation typeid

C++ 关键字typeid有一个魔力:它知道何时使用编译时类型信息以及何时使用运行时类型信息:

#include <iostream>
#include <typeinfo>
using namespace std;
struct Interface      { virtual void f() = 0;               };
struct S1 : Interface {         void f() { cout << "S1\n"; }};
struct S3 : S1        {         void f() { cout << "S3\n"; }};
int main() {
    S1 s1;
    cout << typeid(s1).name() << endl;
    S1* ps = new S3;
    cout << typeid(ps).name() << endl;
    cout << typeid(*ps).name() << endl;
    delete ps;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

程序打印:

struct S1
struct S1 * __ptr64
struct S3
Run Code Online (Sandbox Code Playgroud)

我的问题: gcc/clang 编译器是否有任何编译器宏或 type_traits :它暴露了typeid魔法并告诉我们typeid(*ps)是编译时确定的还是运行时确定的?

The*_*ind 7

看一下这个:

template<typename T>
constexpr auto my_typeId(const T& value) {
    auto compileTimeChecked{ true };
    const auto& typeId = typeid(compileTimeChecked = false, value);
    return std::pair<
        decltype(compileTimeChecked),
        decltype(typeId)
    >{ compileTimeChecked, typeId };
}
Run Code Online (Sandbox Code Playgroud)

该对的第一个参数trueiftypeid在编译时解析。false否则。第二个成员是对已解析类型信息的引用const std::type_info &


这里的技巧是typeid语义会根据它所采用的参数而变化。如果参数是多态类的实例,则typeid实际上在运行时计算表达式,并且 的副作用发挥作用compileTimeChecked = false。否则typeid不计算表达式(因此,永远不会发生),而只是在编译时compileTimeChecked = false获取解析的静态类型。value

编辑:正如user17732522 在评论中指出的那样,请注意,当value是多态纯右值时,my_typeId函数实际上在运行时对其进行求值,这与typeid如果直接传递则静态解析类型不同。在使用函数时,这种差异显然是不可能消除的,只是因为函数调用在 C++ 中的工作方式。

  • @TheDreamsWind 如果操作数是多态类型的纯右值,那么您的“my_typeId”将声称它没有经过编译时检查,而实际上它是“typeid”,例如https://godbolt.org/z/7Tbee17oq。但是您无法在函数调用中区分 xvalue 和纯右值,因此对此您无能为力。我能想到的唯一方法是不直接获取操作数,而是使用一个“decltype(auto)” lambda,其中 typeid 操作数作为“return”操作数,然后在“my_typeId”中的“typeid”内部调用。 (2认同)