Compile-Time Polymorphism with Templates

Can I use templates to implement compile-time polymorphism?

Yes, you can use templates to implement compile-time polymorphism in C++. This is often referred to as static polymorphism or compile-time polymorphism, as opposed to runtime polymorphism achieved through virtual functions and inheritance.

Compile-time polymorphism with templates allows you to write code that works with different types without the overhead of virtual function calls. It's resolved at compile-time, which can lead to better performance compared to runtime polymorphism.

Here's an example demonstrating compile-time polymorphism using templates:

#include <iostream>
#include <list>
#include <vector>

// Base template for Shape
template <typename T>
class Shape {
 public:
  void Draw() const {
    static_cast<const T*>(this)->DrawImpl();
  }
};

// Derived "class" Circle
class Circle : public Shape<Circle> {
 public:
  void DrawImpl() const {
    std::cout << "Drawing a circle\n";
  }
};

// Derived "class" Square
class Square : public Shape<Square> {
 public:
  void DrawImpl() const {
    std::cout << "Drawing a square\n";
  }
};

// Function template that works with any Shape
template <typename T>
void DrawShape(const Shape<T>& shape) {
  shape.Draw();
}

int main() {
  Circle circle;
  Square square;

  DrawShape(circle);
  DrawShape(square);

  // We can even use it with containers
  std::vector<Shape<Circle>*> circles = {
    new Circle, new Circle
  };
  std::list<Shape<Square>*> squares = {
    new Square, new Square
  };

  for (auto& c : circles) DrawShape(*c);
  for (auto& s : squares) DrawShape(*s);

  // Clean up
  for (auto& c : circles) delete c;
  for (auto& s : squares) delete s;
}
Drawing a circle
Drawing a square
Drawing a circle
Drawing a circle
Drawing a square
Drawing a square

This example demonstrates the Curiously Recurring Template Pattern (CRTP), a form of compile-time polymorphism. Here's how it works:

  1. We define a base Shape template that declares a Draw() function. This function calls DrawImpl() on the derived class using static_cast.
  2. Derived classes (like Circle and Square) inherit from Shape<DerivedClass> and implement their own DrawImpl() method.
  3. The DrawShape() function template can work with any type derived from Shape<T>.
  4. At compile-time, the correct DrawImpl() method is selected based on the actual type of the object.

Key benefits of this approach:

  1. Performance: There's no virtual function call overhead. The correct function is determined at compile-time.
  2. Flexibility: You can add new "derived" classes without modifying existing code.
  3. Static checking: Errors, like forgetting to implement DrawImpl(), are caught at compile-time.

Some considerations:

  1. Code bloat: Each instantiation of the template generates new code, which can increase compile times and binary size.
  2. Debugging: Template-heavy code can be more challenging to debug due to complex error messages.
  3. Lack of runtime polymorphism: You can't have containers of mixed shape types or change behavior at runtime.

Compile-time polymorphism with templates is a powerful technique in C++. It's particularly useful in scenarios where you need high performance and know the types you're working with at compile-time. However, it's not a replacement for runtime polymorphism in all cases. The choice between compile-time and runtime polymorphism depends on your specific requirements for flexibility, performance, and design.

Class Templates

Learn how templates can be used to create multiple classes from a single blueprint

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Partial Specialization of Class Templates
Is it possible to partially specialize a class template?
Creating Templates with Variable Number of Parameters
How can I create a template that works with an arbitrary number of type parameters?
Default Values for Non-Type Template Parameters
Is it possible to have default values for non-type template parameters?
Constraining Template Arguments
How can I create a template that only accepts certain types of arguments?
Typename vs Class in Template Declarations
What's the difference between typename and class in template parameter declarations?
Creating Class Templates with Multiple Types
How can I create a class template that works with both primitive types and user-defined types?
Best Practices for Naming Template Parameters
What are the best practices for naming template parameters?
Specializing Class Templates
How can I specialize a class template for specific types?
Using Template Parameters in Constructors
Can I use template parameters in the constructor of a class template?
Template Methods in Non-Template Classes
How do I create a template method within a non-template class?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant