So I was reading this article about type erasure. But the code in that article seems partially incorrect, for example:
Repaired link
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.
Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to: Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded.
C++ type erasure is not Java type erasure In Java, it means the procedure applied by the compiler when you write a “generic” function — which looks deceptively similar to a C++ template, but is not a template! The intent is that you could call find(someShapes, myShape) or find(someAnimals, myCat) .
Type-erasure simply means "erasing" a specific type to a more abstract type in order to do something with the abstract type (like having an array of that abstract type). And this happens in Swift all the time, pretty much whenever you see the word "Any."
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() };
}
[Live example]
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With