如何在STL容器中存储模板化的异构对象

时间:2012-12-13 18:09:29

标签: c++ templates visual-c++ generics stl

问题是关于在MS Visual C ++ 11中开发的代码,只能访问STL,没有Boost。

有一个包装器模板类,大致有这个标题:

template <typename Payload>
class Wrapper {
  Payload p;
  std::string src;
  Wrapper( std::string, Payload );

  Payload get();      // returns payload
  void set(Payload);  // replaces payload
  void operator ()(); // uses payload
}

Payload可能是任何东西 - 指针,整数,甚至是重物。

稍后,Wrapper需要进入容器,例如std::vector - 但不管它们的具体参数类型如何。这给我带来了麻烦,因为容器需要同质的元素。

我已经尝试了基类建议like this from KennyTM,但它给了我一些方法get()set()的问题 - 当从向量中使用时需要强制转换(?)因为元素看起来如果在该答案建议的模式中使用,则像基类一样。

2 个答案:

答案 0 :(得分:5)

为此你需要使用某种类型的擦除。从最基本的(提供基本类型,通过指针存储元素到基础)到更高级的解决方案,如boost ::任何你可以选择(我知道你提到没有提升,但你总是可以看看实现) 。或者,如果有效负载集已知且相对较小,则可以使用变量方法(类似于boost :: variant),但是单次使用可能更难实现。

答案 1 :(得分:3)

template<typename Payload>
struct Wrapper;

struct WrapperBase {
  std::string src;
  WrapperBase( std::string s ):src(s) {}
  template<typename Payload>
  Payload get() const;
  template<typename Payload>
  void set(Payload);
  virtual void operator ()() = 0; // uses payload
};

template <typename Payload>
struct Wrapper {
  Payload payload;
  Wrapper( std::string s, Payload p ):WrapperBase(s),payload(p) {}

  Payload get() const { return payload; };      // returns payload
  void set(Payload p) { payload = p; };  // replaces payload
  virtual void operator()() override; // todo
}

template<typename Payload>
Payload WrapperBase::get() const {
  Assert(dynamic_cast<Wrapper<Payload> const*>(this));
  return static_cast<Wrapper<Payload> const*>(this)->get();
}
template<typename Payload>
void WrapperBase::set(Payload p) {
  Assert(dynamic_cast<Wrapper<Payload>*>(this));
  static_cast<Wrapper<Payload>*>(this)->set(p);
}

WrapperBase的用户,如果想要设置/获取有效负载,则需要知道有效负载的类型。如果您不知道,可以使用dynamic_cast<Wrapper<Payload>*>来确定给定的WrapperBase是否是特定种类。

这没有值语义,因此您需要将vector智能指针存储到WrapperBase而不是实际实例。 std::shared_ptrstd::unique_ptr是不同行为的好候选人。

如果存在Payloads的有限有界集,则访问者模式可以正常工作。

如果您需要值语义,那么存储实际有效负载的pImpl模式可以使用克隆operator=的手动pImpl执行此操作。

询问“你持有T类型”是可能的,但通常类似于dynamic_cast