typeid 演算子
型の情報を問い合わせます。
多相オブジェクトの動的な型を知る必要がある場合および静的な型の識別のために使用されます。
構文
typeid( type )
|
(1) | ||||||||
typeid( expression )
|
(2) | ||||||||
typeid を使用する前にヘッダ <typeinfo> がインクルードされていなければなりません (このヘッダがインクルードされていない場合、キーワード typeid の使用は ill-formed です)。
typeid 式は多相型 const std::type_info またはそこから派生した何らかの型の静的記憶域期間を持つオブジェクトを参照する lvalue 式です。
説明
std::type_info オブジェクトを参照します。 type が参照型の場合、結果は参照先の型を表す std::type_info オブジェクトを参照します。typeid 式はその式を評価し、その式の動的な型を表す std::type_info オブジェクトを参照します。 その glvalue 式がポインタに単項 * 演算子を適用することによって取得され、そのポインタがヌルポインタ値である場合は、 std::bad_typeid 型または std::bad_typeid から派生した型の例外が投げられます。typeid は式を評価せず、その std::type_info オブジェクトはその式の静的な型を表します。 左辺値から右辺値、配列からポインタ、関数からポインタへの変換は行われません。 しかし prvalue の引数の対する一時具体化は (形式的には) 行われます。 typeid はその結果のオブジェクトの型を調べます。 (C++17以上)すべての場合において、 typeid は cv 修飾子を無視します (つまり typeid(const T) == typeid(T) です)。
typeid の被演算子がクラス型またはクラス型への参照の場合、そのクラス型は不完全型であってはなりません。
typeid が構築中または破棄中のオブジェクトに対して使用された場合 (コンストラクタやデストラクタの中で (コンストラクタの初期化子リストやデフォルトメンバ初期化子も含みます))、その typeid によって参照される std::type_info オブジェクトは構築されているまたは破棄されているクラスを表します (それが最も派生したクラスでなくても)。
キーワード
ノート
多相型の式に適用されたとき、 typeid 式の評価は実行時のオーバーヘッド (仮想テーブルの検索) が発生する可能性があり、そうでなければ、 typeid 式はコンパイル時に解決されます。
typeid によって参照されるオブジェクトに対してプログラムの終了時にデストラクタが実行されるかどうかは未規定です。
同じ型に対する typeid 式のすべての評価が同じ std::type_info のインスタンスを参照することは保証されていませんが、それらの type_info オブジェクトの std::type_info::hash_code は同一です。 それらの std::type_index も同様です。
const std::type_info& ti1 = typeid(A);
const std::type_info& ti2 = typeid(A);
assert(&ti1 == &ti2); // 保証されていない
assert(ti1.hash_code() == ti2.hash_code()); // 保証されている
assert(std::type_index(ti1) == std::type_index(ti2)); // 保証されている
例
この例は type_info::name が完全な型名を返す処理系のひとつを使用して出力を表示しています。 gcc 等を使用する場合は c++filt -t を通してフィルタしてください。
#include <iostream>
#include <string>
#include <typeinfo>
struct Base {}; // 非多相
struct Derived : Base {};
struct Base2 { virtual void foo() {} }; // 多相
struct Derived2 : Base2 {};
int main() {
int myint = 50;
std::string mystr = "string";
double *mydoubleptr = nullptr;
std::cout << "myint has type: " << typeid(myint).name() << '\n'
<< "mystr has type: " << typeid(mystr).name() << '\n'
<< "mydoubleptr has type: " << typeid(mydoubleptr).name() << '\n';
// std::cout << myint は多相型の glvalue 式です。 これは評価されます。
const std::type_info& r1 = typeid(std::cout << myint);
std::cout << '\n' << "std::cout<<myint has type : " << r1.name() << '\n';
// std::printf() は多相型の glvalue 式ではありません。 これは評価されません。
const std::type_info& r2 = typeid(std::printf("%d\n", myint));
std::cout << "printf(\"%d\\n\",myint) has type : " << r2.name() << '\n';
// 非多相 lvalue は静的型です。
Derived d1;
Base& b1 = d1;
std::cout << "reference to non-polymorphic base: " << typeid(b1).name() << '\n';
Derived2 d2;
Base2& b2 = d2;
std::cout << "reference to polymorphic base: " << typeid(b2).name() << '\n';
try {
// ヌルポインタの逆参照。 非多相式の場合は可です。
std::cout << "mydoubleptr points to " << typeid(*mydoubleptr).name() << '\n';
// ヌルポインタの逆参照。 多相 lvalue の場合は不可です。
Derived2* bad_ptr = nullptr;
std::cout << "bad_ptr points to... ";
std::cout << typeid(*bad_ptr).name() << '\n';
} catch (const std::bad_typeid& e) {
std::cout << " caught " << e.what() << '\n';
}
}
出力例:
myint has type: int
mystr has type: std::basic_string<char, std::char_traits<char>, std::allocator<char> >
mydoubleptr has type: double*
50
std::cout<<myint has type : std::basic_ostream<char, std::char_traits<char> >
printf("%d\n",myint) has type : int
reference to non-polymorphic base: Base
reference to polymorphic base: Derived2
mydoubleptr points to double
bad_ptr points to... caught std::bad_typeid