【问题标题】:What is type erasure in C++?什么是 C++ 中的类型擦除?
【发布时间】:2016-04-21 07:25:24
【问题描述】:

所以我正在阅读this article about type erasure。但是那篇文章中的代码似乎部分不正确,例如:

template <typename T>
class AnimalWrapper : public MyAnimal
{
    const T &m_animal;

public:
    AnimalWrapper(const T &animal)
        : m_animal(animal)
    { }

    const char *see() const { return m_animal.see(); }
    const char *say() const { return m_animal.say(); }
};

紧随其后

void pullTheString()
{
    MyAnimal *animals[] = 
    {
        new AnimalWrapper(Cow()), /* oO , isn't template argument missing? */
        ....
    };
}

这些错误使我不愿继续阅读本文。

无论如何;谁能通过简单的例子教一下 C++ 中的类型擦除是什么意思?

我想了解它以了解 std::function 的工作原理,但无法理解它。

【问题讨论】:

  • 您要么需要传递&lt;T&gt;,要么使用推导出T 并传递&lt;T&gt; 的函数。即template&lt;class T&gt; MyAnimal* WrapAnimal(T const&amp; t){return new AnimalWrapper&lt;T&gt;(t);},并将new AnimalWrapper 替换为WrapAnimal
  • @NathanOliver 在那个问题中,OP 已经知道类型擦除的基本概念。
  • 我没有看到错误。不会简单地推导出模板参数吗?
  • @AdrianMcCarthy 先生,类模板不是这种情况,构造函数不会为类模板推断模板参数 AFAIK。

标签: c++ type-erasure


【解决方案1】:

这是一个非常简单的类型擦除示例:

// Type erasure side of things

class TypeErasedHolder
{
  struct TypeKeeperBase
  {
    virtual ~TypeKeeperBase() {}
  };

  template <class ErasedType>
  struct TypeKeeper : TypeKeeperBase
  {
    ErasedType storedObject;

    TypeKeeper(ErasedType&& object) : storedObject(std::move(object)) {}
  };

  std::unique_ptr<TypeKeeperBase> held;

public:
  template <class ErasedType>
  TypeErasedHolder(ErasedType objectToStore) : held(new TypeKeeper<ErasedType>(std::move(objectToStore)))
  {}
};

// Client code side of things

struct A
{
  ~A() { std::cout << "Destroyed an A\n"; }
};

struct B
{
  ~B() { std::cout << "Destroyed a B\n"; }
};

int main()
{
  TypeErasedHolder holders[] = { A(), A(), B(), A() };
}

[Live example]

如您所见,TypeErasedHolder 可以存储任意类型的对象,并正确地破坏它们。重要的一点是它不会对支持的类型施加任何限制(1):例如,它们不必从公共基础派生。


(1) 当然,除了是可移动的。

【讨论】:

  • 嗯,你为什么不使用&amp;&amp;(通用引用(?))作为TypeErasedHolderstd::forward的构造函数参数将其传递给TypeKeeper? (在这里试图理解,似乎你总是在复制一个然后从那个副本移动而不是移动原始对象)
  • @JonasWielicki 保持示例的“非常简单”方面。使用转发引用还需要使用std::remove_reference 作为TypeKeeper 的模板参数,等等。
  • 感谢您的澄清!
  • @AngelusMortis 现在代码中没有转发引用(以前称为“通用引用”),只是一个普通的旧右值引用。但是,如果您愿意,我也可以删除它(或者干脆完全摆脱移动,并依靠普通的旧 const&amp; 并复制)。
  • (2) 当然可以销毁。顺便说一句,可移动的要求很容易解决:添加基于位置的构造。 template&lt;class T&gt; struct emplace_as_t{}; template&lt;class T&gt; emplace_as_t&lt;T&gt; emplace_as = {}; 然后添加 ctor template&lt;class T, class...Args&gt; TypeErasedHolder(emplace_as_t&lt;T&gt;, Args&amp;&amp;...args) 等。但这不是基本类型擦除。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多