C++ で typeid 演算子を使用する
この記事では、C++ で typeid
演算子を使用する方法を説明およびデモンストレーションします。
C++ で typeid
演算子を使用してオブジェクトの型名を取得する
typeid
演算子を使用して、指定された式またはオブジェクトの型情報を取得できます。<typeinfo>
ヘッダーで定義されている std::type_info
標準ライブラリタイプへの参照を返します。
std::type_info
オブジェクトには、引数オブジェクトの基になる型を説明する文字列を返すために使用できるメンバー関数 name
があります。typeid
によって取得される型情報は実装に依存することに注意してください。つまり、次のコード例に示すように、最も一般的なコンパイラ gcc
と clang
はマングルされた名前を返します。
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
を使用して修正できます。一般に、const
、volatile
、&
、および&&
修飾子を持つオブジェクトはすべて、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&