C++の型名を読みやすく!typeidの結果をデマングルする方法

C++でデバッグやログ出力を行う際、typeid(some_variable).name() を使って変数の型名を取得することがあります。しかし、特にテンプレートや名前空間を使った複雑な型の場合、出力された文字列が N2NS5InnerIiE のような暗号めいたものになり、困惑した経験はありませんか?

これはC++の**「名前マングリング」という仕組みによるものです。この記事では、マングリングとは何か、そしてマングリングされた名前を人間が読める形式に戻す「デマングリング」**の方法を、GCC/Clang環境向けに分かりやすく解説します。


目次

なぜ必要?「名前マングリング」の仕組み

C++では、同じ名前の関数を引数の型を変えて複数定義する**「オーバーロード」や、同じ名前のクラスや関数を異なる「名前空間」に定義することが可能です。また、「テンプレート」**を使えば、一つの定義から多数の異なる型を生成できます。

このため、コンパイラやリンカは、これらの同名の識別子を内部的に区別できなければなりません。そこで、型情報や名前空間などを含んだ一意な名前を自動的に生成します。このプロセスが**名前マングリング(Name Mangling)**です。

typeid(T).name() が返すのは、この内部的に使われるマングリングされた名前なのです。


abi::__cxa_demangle で名前を復元する

マングリングされた名前はコンピュータにとっては都合が良いですが、人間には読めません。そこで、この名前を元の分かりやすい形式に戻す「デマングリング」のための関数が用意されています。

GCCやClangなど、Itanium C++ ABIに準拠したコンパイラでは、<cxxabi.h> ヘッダにある abi::__cxa_demangle という関数が利用できます。

この関数は、マングリングされたC文字列を引数に取り、デマングリングされたC文字列を返します。内部で std::malloc() を使ってメモリを確保するため、戻り値のポインタは呼び出し側が std::free() で解放しなければならない点に注意が必要です。


実践!サンプルコードでデマングリングを体験

それでは、実際に __cxa_demangle を使って、複雑なテンプレート型の名前をデマングリングしてみましょう。

#include <iostream>
#include <vector>
#include <string>
#include <typeinfo>
#include <cxxabi.h> // __cxa_demangle を使うために必要
#include <memory>   // std::unique_ptr を使うために必要
#include <cstdlib>  // std::free を使うために必要

// カスタムの名前空間とテンプレートクラスを定義
namespace MyLibrary {
    template<typename T>
    struct CustomBox {};
}

// デマングリングされた名前を安全に管理するためのヘルパー関数
std::string demangle(const char* mangled_name) {
    int status = 0;
    // __cxa_demangle が確保したメモリを unique_ptr で管理し、自動的に free する
    std::unique_ptr<char, void(*)(void*)> result(
        abi::__cxa_demangle(mangled_name, nullptr, nullptr, &status),
        std::free
    );
    return (status == 0) ? result.get() : mangled_name;
}

int main() {
    // 調査対象の複雑な型の変数を定義
    std::vector<MyLibrary::CustomBox<std::string>> my_complex_type;

    // 1. typeid を使ってマングリングされた名前を取得
    const char* mangled_name = typeid(my_complex_type).name();

    // 2. ヘルパー関数を使ってデマングリング
    std::string demangled_name = demangle(mangled_name);
    
    // 3. 結果を比較して表示
    std::cout << "Mangled  : " << mangled_name << std::endl;
    std::cout << "Demangled: " << demangled_name << std::endl;

    return 0;
}

実行結果の例(GCC/Clang)

Mangled  : St6vectorIN9MyLibrary9CustomBoxISsEESaIS2_EE
Demangled: std::vector<MyLibrary::CustomBox<std::string>, std::allocator<MyLibrary::CustomBox<std::string> > >

コードのポイント解説

  • #include <cxxabi.h>: abi::__cxa_demangle 関数を利用するために必須のヘッダです。
  • demangle ヘルパー関数: __cxa_demangle はC言語スタイルのメモリ管理(malloc/free)を要求します。std::unique_ptr とカスタムデリータ std::free を組み合わせることで、メモリリークの心配がない安全なC++コードにしています。
  • 処理の流れ: typeid で取得したマングリング済みの名前を demangle 関数に渡し、人間が読める文字列に変換してから出力しています。結果は一目瞭然で、元の型名が正確に復元されていることが分かります。

まとめ

abi::__cxa_demangle を使うことで、typeid が返す不可解な文字列を、デバッグやログ出力に役立つ分かりやすい型名に変換できます。

特に、テンプレートを多用する現代的なC++のコードにおいて、動的な型情報を扱う際にこのテクニックは非常に有効です。メモリ管理にだけ注意すれば、あなたのプログラムの可読性とデバッグ効率を大きく向上させてくれるでしょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次