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

时间:2016-03-03 08:51:43

标签: c++ templates types casting

我们假设我们有一个类如下:

class AbstractContainer{
    ...
};

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

现在还有另一个类,它有一个成员变量,可以存储其中一个容器。但是,模板类型不应修复。因此,不是将成员变量声明为Container类型,而是声明为类型AbstractContainer*,因此指向基类。无论模板参数如何,此指针都应该能够存储所有类型的Container类。

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

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

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<int>*Container<float>*,例如在另一个函数中:

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。所以它不是一个让它成为虚拟的选择。

5 个答案:

答案 0 :(得分:2)

你可以做

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 :(得分:1)

虽然Jarod42's answer更好,但一种方法是使用typeid

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

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

答案 2 :(得分:1)

可能你的回答是Curiously recurring template pattern

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()
    {

    }
};

答案 3 :(得分:0)

另一种选择:

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

你不需要基类,没有继承,没有演员阵容。

答案 4 :(得分:0)

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值

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

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