简体   繁体   English

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

[英]How to store templated heterogeneous objects in an STL container

The question is about a code developed in MS Visual C++ 11, with access only to STL, no Boost. 问题是关于在MS Visual C ++ 11中开发的代码,只能访问STL,没有Boost。

There is a wrapper template class, roughly with this header: 有一个包装器模板类,大致有这个标头:

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 may be anything - pointer, int, even heavy object. Payload可能是任何东西 - 指针,整数,甚至是重物。

Later, Wrapper s need to go in a container, like std::vector - but regardless of their specific parameter type. 后来, Wrapper需要进入一个容器,比如std::vector - 但不管它们的具体参数类型如何。 And that gives me trouble because container needs homogeneous elements. 这给我带来了麻烦,因为容器需要同质的元素。

I have tried the base class suggestions like this from KennyTM , however it gives me some issues with methods get() and set() - those need cast (?) when used from a vector because elements look like a base class if used in the pattern suggested by that answer. 我已经尝试过KennyTM这样的基类建议,但是它给了我一些方法get()set() - 当从向量中使用时需要强制转换 (?)因为元素看起来像一个基类,如果在该答案提出的模式。

For that you will need to use some sort of type erasure. 为此,您需要使用某种类型的擦除。 From the most basic (provide a base type, store the elements by pointer to the base) to fancier solutions like boost::any you get to choose (I know you mentioned no boost, but you can always take a look at the implementation). 从最基本的(提供基本类型,通过指针存储元素到基础)到更高级的解决方案,如boost ::任何你可以选择(我知道你提到没有提升,但你总是可以看看实现) 。 Alternatively you could use a variant approach (similar to boost::variant) if the set of payloads is known and relatively small, but that might be harder to implement for a single use. 或者,如果有效载荷集是已知的并且相对较小,则可以使用变体方法(类似于boost :: variant),但是对于单次使用可能更难实现。

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

Users of a WrapperBase , if they want to set/get the payload, need to know what the type of the payload is. 如果WrapperBase用户想要设置/获取有效负载,则需要知道有效负载的类型。 You can use dynamic_cast<Wrapper<Payload>*> to figure out if a given WrapperBase is a specific kind if you don't know. 如果您不知道,可以使用dynamic_cast<Wrapper<Payload>*>来确定给定的WrapperBase是否是特定类型。

This doesn't have value semantics, so you'll want to store a vector of smart pointers to WrapperBase rather than actual instances. 这没有值语义,因此您需要将智能指针的vector存储到WrapperBase而不是实际实例。 std::shared_ptr or std::unique_ptr are good candidates with very different behavior. std::shared_ptrstd::unique_ptr是具有非常不同行为的好候选者。

If there is a finite bounded set of Payloads , a visitor pattern can work. 如果存在有限的Payloads集,则访问者模式可以起作用。

If you need value semantics, a pImpl pattern that stores the actual payload can do that with manual operator= that clones the pImpl . 如果您需要值语义,那么存储实际有效负载的pImpl模式可以使用手动operator=来克隆pImpl

Asking "do you hold type T " is possible, but generally is similar to a dynamic_cast . 询问“你持有T型”是可能的,但通常类似于dynamic_cast

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM