Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is type erasure in C++?

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.

like image 497
Angelus Mortis Avatar asked Jan 15 '16 16:01

Angelus Mortis


People also ask

What is type erasure and why do we need 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.

Do C++ templates use type erasure?

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) .

What is type erasure in Swift?

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."


1 Answers

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.

like image 122
Angew is no longer proud of SO Avatar answered Nov 16 '22 04:11

Angew is no longer proud of SO