C ++:存储/记住模板类的类型

C++: store/remember type of template class

假设我们有一个类似以下的类:

1
2
3
4
5
6
7
8
class AbstractContainer{
    ...
};

template <typename T>
class Container : public AbstractContainer {
    T someFunction();
};

现在,有另一个类具有一个成员变量,该成员变量将存储这些容器之一。但是,模板类型不应固定。因此,不是将成员变量声明为Container类型,而是将其声明为AbstractContainer*类型,因此是基类的指针。不管模板参数如何,此指针都应该能够存储所有类型的Container类。

1
2
3
4
5
6
7
class Interface{
public:
    Interface();
    void doSth();
private:
    AbstractContainer* container;
};

假设容器是在Interface类的构造函数中构造的,如下所示:

1
2
3
4
5
6
7
8
Interface::Interface(){
    if (/* some condition */)
        this->container = new Container<int>(25);
    } else {
        this->container = new Container<float>(25);
    }
    //here I'd need to remember of which type container is: int or float
}

因此,在这里我需要以某种方式存储我的容器是哪种类型(intfloat)。在程序的这一点上我知道它,它是完全确定性的。我需要存储它,因为稍后可能需要将AbstractContainer*强制转换回Container*Container*,例如在另一个函数中:

1
2
3
4
5
6
7
8
void Interface::doSth(){
    //here I have to recall what the type was
    if(/* type was int */) {
        dynamic_cast<Container<int>&>(*(this->container)).someFunction();
    } else {
        dynamic_cast<Container<float>&>(*(this->container)).someFunction();
    }
}

我曾考虑过使用包含所有受支持类型的值的enum并将该类型保存在该枚举类型的其他成员变量中。然后,我必须做一个switch语句,检查所有不同的可能性并执行正确的转换。但是,我想知道是否可能没有更简单的方法。

我基本上想做的是存储Interface的构造函数中使用的类型,然后在Interface::doSth中调用它。

编辑:我必须弄清楚函数someFunction取决于模板参数T。因此,使其成为虚拟的不是一种选择。


你可以做

1
2
3
4
5
6
7
void Interface::doSth(){
    if (auto* c_int = dynamic_cast<Container<int>*>(this->container)) {
        c_int->someFunction();
    } else if (auto* c_float = dynamic_cast<Container<float>*>(this->container)) {
        c_float->someFunction();
    }
}

但是,为什么不将someFunction()移到基类中呢? 并使用虚拟方法?


可能是您的答案是奇怪的重复模板模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
template<class T, template<class> class U>
class AbstractContainer
{
    void interface()
    {
        static_cast<U< T > *>(this)->implementation();
    }
};

template<class T>
class Container : public AbstractContainer<T, Container>
{
    void implementation()
    {

    }
};


尽管Jarod42的答案更好,但是一种实现方法是使用typeid

1
2
3
4
5
6
7
8
9
10
11
void doSth()
{
    if (typeid(*container).hash_code() == typeid(Container<int>).hash_code())
    {
        cout <<"int" << endl;
    }
    else if (typeid(*container).hash_code() == typeid(Container<float>).hash_code())
    {
        cout <<"float" << endl;
    }
}

但是在基类中至少需要一个虚函数。 例如,您可以创建虚拟析构函数。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
class AbstactObject {
public:
  virtual ~AbstractObject() = 0;

  virtual AbstractObject &doSomething() = 0;
}

template<class T>
class Object : AbstactObject {
public:
  virtual ~Object();

  virtual Object< T > &doSomething();

  T &get();
private:
  T t;
}

class AbstractContainer {
public:
  virtual ~AbstractObject() = 0;

  virtual AbstractObject &doSomething();

private:
  AbstractObject *obj;
};

template<class T>
class Container : AbstactContainer {
public:
  virtual ~Container();

  virtual Object< T > &doSomething() {
    return obj->doSomething();
  };
}

class Interface {
public:
  Interface();
  void doSth();
private:
  AbstractContainer* container;
};


Interface::Interface() {
  if (/* some condition */)
    container = new Container<int>(25);
  } else {
    container = new Container<float>(25);
  }
}

void Interface::doSth() {
  auto obj = container->doSomething();
  auto val = obj.get();    
}

当你想获得T值时

1
2
auto obj = container->doSomething();
auto val = obj.get();

请检查:协变返回类型
https://zh.wikipedia.org/wiki/Covariant_return_type


另一种选择:

1
2
3
4
template <class T>
T doSth(Container< T > &container){
    return container.someFunction(); //assume someFunction returns a T
}

您不需要基类,继承,演员表。