プログラミング言語C++の typeid 演算子における、参照型および cv修飾(const, volatile)の扱いについてメモ。
typeid演算子オペランドに型名(type-id)や式(expression)を指定するとき、下記ルールが適用されることに注意。
- 対象が参照型(
T&
,T&&
)の場合、参照先の型T
として扱う。 - トップレベルの const/volatile 修飾は無視する。
メタ関数のデバッグ時など、関数テンプレートfのテンプレートパラメータTがどの型に推論されたかを確認したいケース(注意:例ではabi::__cxa_demangle
戻り値を解放せずメモリリークするため、デバッグ用途に留めること*1。):
#include <iostream> #include <typeinfo> #include <cxxabi.h> // __cxa_demangle struct A {}; // 適当な型A template <class T> void f(T&&) { // typeid( T ) による確認 std::cout << abi::__cxa_demangle(typeid(T).name(),0,0,0) << std::endl; } A g1() { return {}; } const A g2() { return {}; } volatile A g3() { return {}; } const volatile A g4() { return {}; } int main() { A a = {}; const A ca = {}; volatile A va = {}; const volatile A cva = {}; f(A{}); f(a); f(ca); f(va); f(cva); f(g1()); f(g2()); f(g3()); f(g4()); }
上記コードでは全パターンで単に 型A と出力されてしまい*2、推論されたテンプレートパラメータTの正確な型を識別できない。これを回避するには型T
を適当なクラステンプレートX
に指定し、前掲のtypeid演算子に関するルール適用外とすればよい。
template <class> struct X {}; template <class T> void f(T&&) { // typeid( X<T> ) による確認 std::cout << abi::__cxa_demangle(typeid(X<T>).name(),0,0,0) << std::endl; }
gcc 4.6.3での実行結果:
X<A> X<A&> X<A const&> X<A volatile&> X<A const volatile&> X<A> X<A const> X<A volatile> X<A const volatile>
C++03 5.2.8/p4-5より引用。
4 When
typeid
is applied to a type-id, the result refers to atype_info
object representing the type of the type-id. If the type of the type-id is a reference type, the result of thetypeid
expression refers to atype_info
object representing the referenced type. If the type of the type-id is a class type or a reference to a class type, the class shall be completely-defined. Types shall not be defined in the type-id.
5 The top-level cv-qualifiers of the lvalue expression or the type-id that is the operand oftypeid
are always ignored. [Example:class D { ... }; D d1; const D d2; typeid(d1) == typeid(d2); // yields true typeid(D) == typeid(const D); // yields true typeid(D) == typeid(d2); // yields true typeid(D) == typeid(const D&); // yields true-- end example]