C++ で typeid 演算子を使用する

胡金庫 2023年10月12日
C++ で typeid 演算子を使用する

この記事では、C++ で typeid 演算子を使用する方法を説明およびデモンストレーションします。

C++ で typeid 演算子を使用してオブジェクトの型名を取得する

typeid 演算子を使用して、指定された式またはオブジェクトの型情報を取得できます。<typeinfo> ヘッダーで定義されている std::type_info 標準ライブラリタイプへの参照を返します。

std::type_info オブジェクトには、引数オブジェクトの基になる型を説明する文字列を返すために使用できるメンバー関数 name があります。typeid によって取得される型情報は実装に依存することに注意してください。つまり、次のコード例に示すように、最も一般的なコンパイラ gccclang はマングルされた名前を返します。

Microsoft Visual C++ のような他の実装は、より読みやすい形式で情報を表示します。それでも、前の実装で表示された組み込み型の名前を識別する方法を学ぶことができることを覚えておいてください。たとえば、int オブジェクトは i 文字を返し、int オブジェクトへのポインタは Pi 文字列を返します。

#include <iostream>
#include <string>
#include <typeinfo>

using std::cin;
using std::cout;
using std::endl;
using std::string;

int main() {
  int i1 = 1234;
  string str1("arbitrary string");
  auto ptr = &i1;

  cout << "i1 type: " << typeid(i1).name() << '\n'
       << "str1 type: " << typeid(str1).name() << '\n'
       << "ptr type: " << typeid(ptr).name() << endl;

  const std::type_info& r1 = typeid(i1);
  cout << '\n' << "i1 type: " << r1.name() << '\n';

  return EXIT_SUCCESS;
}

出力:

i1 type: i
str1 type: NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
ptr type: Pi

i1 type: i

一方、オブジェクトへの参照に対して typeid コマンドを呼び出すと、取得された型情報が常に正確であるとは限らず、場合によっては不可解すぎて読み取れないことがわかります。次の例は、typeid 演算子への 2 回目の呼び出しが型情報を誤って返すような場合を示しています。

#include <iostream>
#include <string>
#include <typeinfo>

using std::cout;
using std::endl;

struct Base {};
struct Derived : Base {};

struct Base2 {
  virtual void foo() {}
};
struct Derived2 : Base2 {};

int main() {
  Derived d1;
  Base& b1 = d1;
  cout << "non-polymorphic base: " << typeid(b1).name() << '\n';

  Derived2 d2;
  Base2& b2 = d2;
  cout << "polymorphic base: " << typeid(b2).name() << '\n';

  return EXIT_SUCCESS;
}

出力:

non-polymorphic base: 4Base
polymorphic base: 8Derived2

この動作は、型情報を正確に返すことができる BoostTypeIndex ライブラリ関数 type_id_with_cvr を使用して修正できます。一般に、constvolatile&、および&&修飾子を持つオブジェクトはすべて、typeid 演算子が使用されている場合に誤った型情報を引き起こします。したがって、type_id_with_cvr 関数を使用することをお勧めします。

次のコード例では、Boost ライブラリがシステムにインストールされている必要があり、type_id_with_cvr 関数は boost::typeindex 名前空間の下にあります。

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

using boost::typeindex::type_id_with_cvr;
using std::cout;
using std::endl;

struct Base {};
struct Derived : Base {};

struct Base2 {
  virtual void foo() {}
};
struct Derived2 : Base2 {};

int main() {
  Derived d1;
  Base& b1 = d1;

  Derived2 d2;
  Base2& b2 = d2;

  cout << type_id_with_cvr<decltype(b1)>().pretty_name() << '\n';
  cout << type_id_with_cvr<decltype(b2)>().pretty_name() << '\n';

  return EXIT_SUCCESS;
}

出力:

Base&
Base2&
著者: 胡金庫
胡金庫 avatar 胡金庫 avatar

DelftStack.comの創設者です。Jinku はロボティクスと自動車産業で8年以上働いています。自動テスト、リモートサーバーからのデータ収集、耐久テストからのレポート作成が必要となったとき、彼はコーディングスキルを磨きました。彼は電気/電子工学のバックグラウンドを持っていますが、組み込みエレクトロニクス、組み込みプログラミング、フロントエンド/バックエンドプログラミングへの関心を広げています。

LinkedIn Facebook

関連記事 - C++ Operator