Skip to content

Type Erasure: std::function, std::any and Building Your Own

Beginning of the lesson

Type Erasure: std::function, std::any and Building Your Own

Hiding a concrete type behind a uniform, value-semantic interface

Big Idea: Type erasure is the technique of storing an object of any type behind a fixed, uniform interface, so that callers never see the concrete type again. std::function erases any callable with a given signature; std::any erases any copyable value. Both give you runtime polymorphism without a shared base class and with ordinary value semantics - you copy, move and store them like an int. Under the hood it is a small, disciplined marriage of templates and virtual dispatch, and once you see the pattern you can build your own.
By the end you will be able to:
  • explain what "erasing" a type means and why value semantics matter,
  • use std::function to store heterogeneous callables behind one signature,
  • use std::any and std::any_cast to hold and recover values of unknown type,
  • implement the Concept/Model idiom to build your own type-erased wrapper,
  • reason about the cost: heap allocation, indirection, and the small buffer optimization.

1. The problem: polymorphism without a base class

You already know two ways to write code that works over many types. Templates give compile-time polymorphism: template <class T> stamps out a new function per type, with no runtime cost, but the type leaks into every signature - a std::vector<T> can hold only one T. Virtual functions give runtime polymorphism, but they are intrusive: every stored type must inherit from your base class and be handled through a pointer, so you lose value semantics and cannot store types you do not control (like int or a third-party struct).

Type erasure is the third way. It lets you write a single non-template class - say a Drawable - that can hold any type offering a draw() operation, without that type inheriting anything, and behaves like a plain value you can copy into a std::vector<Drawable>. The concrete type is "erased": after construction the wrapper only remembers how to draw, not what it holds.

Analogy - the universal wall socket. A power socket does not know or care whether you plug in a lamp, a laptop charger or a kettle. It exposes one fixed shape (the interface) and each device adapts to it. The socket has "erased" the device type: it only knows the contract (deliver power), never the concrete appliance. A type-erased wrapper is that socket for C++ objects.

Continue this lesson on YourAIZone

The full lesson has the complete explanation, worked examples, common mistakes, tests with instant checking and an AI tutor. Start right away as a guest, or create an account to keep your progress.

In the full lesson

  • The complete explanation
  • Worked examples
  • Common mistakes and how to avoid them
  • Test questions: 15
  • AI tutor that answers questions about the topic
  • Progress tracking for students, parents and teachers