我想就如何将变量模板模拟为类成员发表意见。这样,您的类中的数据成员依赖于模板,但不依赖于类模板。从概念上讲,可以写成:
class M
{
private:
template<typename T>
SomethingThatCouldDependOnT<T> m_dataMember;
};
我的第一个想法就是做出这样的事情:
#include <iostream>
class A
{
public :
template<typename T>
void myMethod()
{
static int a = 0;
std::cout << "my method : " << a << " calls" << std::endl;
a++;
}
};
int main()
{
A a, b;
a.myMethod<int>();
a.myMethod<int>();
a.myMethod<double>();
b.myMethod<double>();
return 0;
}
但这不起作用,因为myMethod中的静态成员不是每个实例,而是生成每个方法。实际上,它是有道理的,因为myMethod可以被视为一个全局函数,将第一个参数作为A类型的对象(不考虑可见性问题)。所以我提出了另一个想法:
#include <iostream>
#include <vector>
class A
{
public :
A() : i(-1) {}
template<typename T>
void myMethod()
{
static std::vector<int> a;
static int max = 0;
if(i < 0)
{
i = max;
a.push_back(0);
max++;
}
std::cout << "my method : " << a[i] << " calls" << std::endl;
a[i]++;
}
private:
int i;
};
int main()
{
A a, b;
a.myMethod<int>();
a.myMethod<int>();
a.myMethod<double>();
b.myMethod<double>();
return 0;
}
但我真的不喜欢它,即使可以通过重复使用未使用的整数或使用更合适的容器来改进它。
我想在这里可能有更好的解决方案,这就是我要问的原因。
答案 0 :(得分:4)
您可以通过从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
但是,如果您正在使用boost,则可以大大简化:
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;
};
答案 1 :(得分:1)
您只需要一个带有静态成员的额外模板:
#include <iostream>
template<class T>
struct StaticForMyMethod
{
static int value;
};
template<class T>
int StaticForMyMethod<T>::value;
template<typename T>
void myMethod()
{
int& a = StaticForMyMethod<T>::value;
std::cout << "my method : " << a << " calls" << std::endl;
a++;
}
int main() {
myMethod<int>();
myMethod<int>();
myMethod<long>();
myMethod<long>();
}
输出:
my method : 0 calls
my method : 1 calls
my method : 0 calls
my method : 1 calls