最近狂看 C++ 的東西,明明這麼複雜,可是真香 OuO

tl;dr

#include <typeinfo>
#include <cxxabi.h>

template<typename T>
const std::string get_type_name(const T variable) {
    const char* const name = typeid(variable).name();
    int status = -4;
    char* const demangled_name = abi::__cxa_demangle(name, NULL, NULL, &status);
    std::string ret{name};
    if (status == 0) {
        ret = std::string(demangled_name);
        free(demangled_name);
    }
    return ret;
}

typeid operator

typeinfo 中有提供 typeid() 可以取得 type 或是 expression (variable) 的名字 1

Example

#include <iostream>
#include <typeinfo>

int main () {
    int a;
    std::cout << typeid(int).name() << '\n';
    std::cout << typeid(a).name() << '\n';
}

[run]

不過像是 int 只能顯示 i,其他複雜的顯示也不直觀,主要是因為 C++ 會對於型別做修飾 (Name mangling 2),這也是為何 C++ 能夠支援 function overloading,因為編譯過程中型別都會轉成獨一無二的表達方式所以不會造成衝突。

Demangle

<cxxabi.h> 中有提供方法可以讓經過 mangle 的型別轉回可讀性較高的字串。以下範例與上述提到的方法進行比較。

#include <iostream>
#include <string>
#include <typeinfo>
#include <cxxabi.h>


template<typename T>
const std::string get_type_name(const T variable) {
    const char* const name = typeid(variable).name();
    int status = -4;
    char* const demangled_name = abi::__cxa_demangle(name, NULL, NULL, &status);
    std::string ret{name};
    if (status == 0) {
        ret = std::string(demangled_name);
        free(demangled_name);
    }
    return ret;
}

namespace OuO::QuQ {
    struct Foo { };

    template <unsigned int size>
    struct Bar { };
}
using Foo = OuO::QuQ::Foo;


int main () {
    int a;
    std::cout << typeid(a).name() << '\n';
    std::cout << get_type_name(a) << '\n';

    Foo b;
    std::cout << typeid(b).name() << '\n';
    std::cout << get_type_name(b) << '\n';

    OuO::QuQ::Bar<99> c;
    std::cout << typeid(c).name() << '\n';
    std::cout << get_type_name(c) << '\n';

    return 0;
}

[run]

可以從結果看到後者可讀性較高

封面照片 - 執行結果

封面照片 - 執行結果

OuO

我發佈後才被 YouTube 推薦…,不過我最近也看一堆他的影片。

References

Footnotes

  1. typeid operator ↩︎

  2. Name mangling ↩︎