【问题标题】:How to store templated heterogeneous objects in an STL container如何在 STL 容器中存储模板化的异构对象
【发布时间】:2012-12-01 16:44:18
【问题描述】:

问题是关于在 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 可以是任何东西 - 指针、整数,甚至是重对象。

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

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

【问题讨论】:

  • 你需要像boost::any这样的类型擦除类,你可以自己实现,这样你就可以避免Boost。
  • KennyTM 的解决方案只有在您确实可以使用虚拟功能时才适用。你不能在这里因为你的函数的返回类型不兼容。此外,对象只是模板参数不同并不重要。它们仍然是具有不同大小的不同类型,这对容器来说是最重要的。

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


【解决方案1】:

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

【讨论】:

    【解决方案2】:
    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的用户,如果他们想设置/获取payload,需要知道payload的类型。如果您不知道,可以使用dynamic_cast&lt;Wrapper&lt;Payload&gt;*&gt; 来确定给定的WrapperBase 是否是特定类型。

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

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

    如果您需要值语义,存储实际有效负载的pImpl 模式可以通过手动复制pImploperator= 来实现。

    可以询问“您是否持有类型T”,但通常类似于dynamic_cast

    【讨论】:

    • 很有趣,所以我错过了基类中的方法模板等。谢谢,现在试试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-30
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多