これを行うには、type_info ポインターから型固有のデータへのマップを作成します。
次に例を示します。
#include <iostream>
#include <map>
#include <typeinfo>
// Custom comparison operator that uses the std::type_info::before member
// function. Comparing the pointers doesn't work since there is no
// guarantee that the typeid operator always gives you the same object
// for the same type.
struct BeforeType {
bool operator()(const std::type_info *a,const std::type_info *b) const
{
return a->before(*b);
}
};
struct A {
template <typename T>
int &member()
{
return member_map[&typeid(T)];
}
std::map<const std::type_info *,int,BeforeType> member_map;
};
int main(int,char**)
{
A a1, a2;
++a1.member<int>();
++a1.member<int>();
++a1.member<double>();
++a2.member<int>();
std::cout << a1.member<int>() << "\n";
std::cout << a1.member<double>() << "\n";
std::cout << a1.member<float>() << "\n";
std::cout << a2.member<int>() << "\n";
return 0;
}
出力は次のとおりです。
2
1
0
1
さまざまなタイプの値のコンテナに興味がある場合は、次のようなものを使用できます。
#include <iostream>
#include <map>
#include <typeinfo>
struct BeforeType {
bool operator()(const std::type_info *a,const std::type_info *b) const
{
return a->before(*b);
}
};
struct Value {
virtual ~Value() { }
virtual Value *clone() = 0;
};
template <typename T>
struct BasicValue : Value {
T value;
BasicValue() : value() { }
BasicValue(const T &value) : value(value) { }
virtual Value *clone() { return new BasicValue(value); }
};
struct TypeMap {
TypeMap() { }
TypeMap(const TypeMap &that)
{
add(that.value_map);
}
template <typename T>
T &value()
{
ValueMap::iterator iter = value_map.find(&typeid(T));
if (iter==value_map.end()) {
BasicValue<T> *member_ptr = new BasicValue<T>;
value_map.insert(ValueMap::value_type(&typeid(T),member_ptr));
return member_ptr->value;
}
return static_cast<BasicValue<T> *>(iter->second)->value;
}
TypeMap &operator=(const TypeMap &that)
{
clear();
add(that.value_map);
return *this;
}
void clear()
{
while (!value_map.empty()) {
Value *member_ptr = value_map.begin()->second;
value_map.erase(value_map.begin());
delete member_ptr;
}
}
~TypeMap()
{
clear();
}
private:
typedef std::map<const std::type_info *,Value *,BeforeType> ValueMap;
ValueMap value_map;
void add(const ValueMap &value_map)
{
ValueMap::const_iterator iter = value_map.begin(), end = value_map.end();
for (;iter!=end;++iter) {
this->value_map[iter->first] = iter->second->clone();
}
}
};
int main(int,char**)
{
TypeMap type_map;
type_map.value<int>() = 5;
type_map.value<float>() = 2.5;
type_map.value<std::string>() = "hi";
std::cout << type_map.value<int>() << "\n";
std::cout << type_map.value<float>() << "\n";
std::cout << type_map.value<std::string>() << "\n";
return 0;
}
出力は次のとおりです。
5
2.5
hi
ただし、ブーストを使用している場合、これは大幅に簡素化できます。
struct TypeMap {
template <typename T>
T &value()
{
boost::any &any_value = value_map[&typeid(T)];
if (any_value.empty()) {
any_value = T();
}
return *boost::any_cast<T>(&any_value);
}
private:
std::map<const std::type_info *,boost::any,BeforeType> value_map;
};
C++11 では、以下を使用してカスタム比較を取り除くこともできますstd::type_index
。
struct TypeMap {
template <typename T>
T &value()
{
boost::any &any_value = value_map[std::type_index(typeid(T))];
if (any_value.empty()) {
any_value = T();
}
return *boost::any_cast<T>(&any_value);
}
private:
std::map<const std::type_index,boost::any> value_map;
};