前のページ(メタプログラミング)へ / 次のページ(部分特殊化)へ
修飾子の付け外し操作についてです。 例えば const のない型からある型への代入は許されていますが 型自体の自動的な変換はサポートされていません。 特に template 引数として受け取った型の場合、 const を付けるのは簡単ですが外すのは面倒です。 そのような修飾子の付け外しをする template を用意しました。
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T> struct Const {
typedef T WithoutConst;
typedef const T WithConst;
};
template<typename T> struct Const<const T> {
typedef T WithoutConst;
typedef const T WithConst;
};
template<typename T> struct Volatile {
typedef T WithoutVolatile;
typedef const T WithVolatile;
};
template<typename T> struct Volatile<volatile T> {
typedef T WithoutVolatile;
typedef volatile T WithVolatile;
};
template<typename T> struct Reference {
typedef T WithoutReference;
typedef const T WithReference;
};
template<typename T> struct Reference<T&> {
typedef T WithoutReference;
typedef T& WithReference;
};
int main() {
cout << typeid(Const<int>::WithoutConst).name() << endl;
cout << typeid(Const<int>::WithConst).name() << endl;
cout << typeid(Const<const int>::WithoutConst).name() << endl;
cout << typeid(Const<const int>::WithConst).name() << endl;
cout << typeid(Volatile<int>::WithoutVolatile).name() << endl;
cout << typeid(Volatile<int>::WithVolatile).name() << endl;
cout << typeid(Volatile<volatile int>::WithoutVolatile).name() << endl;
cout << typeid(Volatile<volatile int>::WithVolatile).name() << endl;
cout << typeid(Reference<int>::WithoutReference).name() << endl;
cout << typeid(Reference<int>::WithReference).name() << endl;
cout << typeid(Reference<int&>::WithoutReference).name() << endl;
cout << typeid(Reference<int&>::WithReference).name() << endl;
return 0;
}
という感じです。 簡単に説明すると一般的な型を受け付ける template を用意します。 template に対して修飾子が付いた型を特殊化することで 一般的な定義の方を実質的に修飾子が付かない型専用にすることが出来ます。 あとはそれぞれに対して修飾子の付け外しを行います。
同様にポインタの参照外し操作についてです。 ポインタ型に対してポイント先の型を取り出したいことがあります。 そのような場合は以下のような template を利用します。
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T> struct Pointer {
typedef void Pointee;
};
template<typename T> struct Pointer<T*> {
typedef T Pointee;
};
int main() {
cout << typeid(Pointer<int>::Pointee).name() << endl;
cout << typeid(Pointer<int*>::Pointee).name() << endl;
cout << typeid(Pointer<int**>::Pointee).name() << endl;
return 0;
}
手法は修飾子の付け外しと同じようなものです。 ここでは非ポインタ型からポイント先を取り出そうとすると void を返すようになっていますが void* からの取り出しと区別出来ません。 もっと明確にポイント先が存在しないとした方が良いかもしれません。