3

我想听听您对如何将变量模板模拟为类成员的意见。也就是说,您的类中有一个依赖于模板但不依赖于类模板的数据成员。从概念上讲,可以写成:

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;
}

但我真的不喜欢它,即使它可以通过重用未使用的整数或使用更合适的容器来改进。

我想认为它可能对我的问题有更好的解决方案,这就是我问的原因。

4

2 回答 2

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;
};
于 2013-05-18T15:53:06.973 回答
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
于 2013-05-20T10:34:32.043 回答