Reputation: 1554
So I was reading this article about type erasure. But the code in that article seems partially incorrect, for example:
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(); }
};
followed by
void pullTheString()
{
MyAnimal *animals[] =
{
new AnimalWrapper(Cow()), /* oO , isn't template argument missing? */
....
};
}
These mistakes discouraged me from reading any further in the article.
Anyways; can anyone please teach what type erasure in C++ means, with simple examples?
I wanted to learn about it to understand how std::function
works, but couldn't get my head around it.
Upvotes: 20
Views: 6615
Reputation: 171117
Here's a very simple example of type erasure in action:
// 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() };
}
As you can see, TypeErasedHolder
can store objects of an arbitrary type, and destruct them correctly. The important point is that it does not impose any restrictions on the types supported(1): they don't have to derive from a common base, for example.
(1) Except for being movable, of course.
Upvotes: 25