std::type_index
では何が問題か
大量の型を管理するには遅そうです。
#include <typeindex>
#include <map>
#include <iostream>
int main(){
// 型をシーケンシャルなidに変換したい.
std::map<std::type_index, int> type_index_map;
int next_index = 0;
// 生成に累計で O(log(n) * n) 時間が掛かる.
type_index_map[typeid(int)] = next_index++;
type_index_map[typeid(void)] = next_index++;
type_index_map[typeid(const char*)] = next_index++;
// 照合で O(log(n)) 時間掛かる.
std::cout << "int mapped -> " << type_index_map[typeid(int)] << std::endl;
std::cout << "void mapped -> " << type_index_map[typeid(void)] << std::endl;
std::cout << "const char* mapped -> " << type_index_map[typeid(const char*)] << std::endl;
return 0;
}
int mapped -> 0
void mapped -> 1
const char* mapped -> 2
template
関数で静的なint
型変数をラップする
コストがインクリメントとコンパイル時に型ごとに生成される関数コールのみになりなりました。
#include <typeindex>
#include <map>
#include <iostream>
int create_next_id(){
static int i = 0;
return i++;
}
template<class T>
int id(){
static int i = create_next_id();
return i;
}
int main(){
// 型をシーケンシャルなidに変換したい.
std::cout << "int mapped -> " << id<int>() << std::endl;
std::cout << "void mapped -> " << id<void>() << std::endl;
std::cout << "const char* mapped -> " << id<const char*>() << std::endl;
std::cout << "int mapped -> " << id<int>() << std::endl;
return 0;
}
int mapped -> 0
void mapped -> 1
const char* mapped -> 2
int mapped -> 0
注意するべき点
-
create_next_id()
内のstatic
変数を外に出すときに翻訳単位に注意する。 -
id<T>()
の最初の呼び出し順序によって実行ごとのint
値の一意性がないため、実行時に依存しない初期化を必ず伴わせる。 -
template
なクラス内でcreate_next_id()
,id<T>()
を持つ事によりクラスごとで照合結果の一意性が損なわれる。 - ただし意図的に分離して相違なクラス間で比較結果を不正なものにしたい場合はメリットになる。
- 定数時間にこだわる場合は関数コールのコストが
inline
化されているかどうかに注意すること。