CodeNebula
C++20coreadvanced

Constexpr Virtual Functions (C++20 Addition)

C++20 · The Big Four · Compiler flag: -std=c++20

Explanation

Virtual functions can be `constexpr`, enabling compile-time polymorphism.

Real-World Scenario

Evaluate polymorphic behavior at compile time in a graphics engine.

Quick Snippet

snippet.cpp
struct Base { virtual constexpr int f() const { return 0; } };

Full Example

constexpr_virtual.cpp
// CodeNebula - C++20 Example: Constexpr Virtual Functions
// Compile: g++ -std=c++20 -Wall -Wextra -o example constexpr_virtual.cpp

// Demonstrates C++20 constexpr virtual functions: virtual dispatch can now
// happen at compile time when the dynamic type is known.

#include <iostream>
#include <array>

// ------------------------------------------------------------------
// 1. Base class with constexpr virtual functions
// ------------------------------------------------------------------
class Shape {
public:
    constexpr virtual ~Shape() = default;
    constexpr virtual double area() const = 0;
    constexpr virtual const char* name() const = 0;
    constexpr virtual int sides() const { return 0; }
};

// ------------------------------------------------------------------
// 2. Derived classes with constexpr overrides
// ------------------------------------------------------------------
class Circle : public Shape {
    double radius_;
public:
    constexpr explicit Circle(double r) : radius_(r) {}
    constexpr double area() const override { return 3.14159265 * radius_ * radius_; }
    constexpr const char* name() const override { return "Circle"; }
    constexpr int sides() const override { return 0; }
};

class Rectangle : public Shape {
    double w_, h_;
public:
    constexpr Rectangle(double w, double h) : w_(w), h_(h) {}
    constexpr double area() const override { return w_ * h_; }
    constexpr const char* name() const override { return "Rectangle"; }
    constexpr int sides() const override { return 4; }
};

class Triangle : public Shape {
    double base_, height_;
public:
    constexpr Triangle(double b, double h) : base_(b), height_(h) {}
    constexpr double area() const override { return 0.5 * base_ * height_; }
    constexpr const char* name() const override { return "Triangle"; }
    constexpr int sides() const override { return 3; }
};

// ------------------------------------------------------------------
// 3. constexpr function using virtual dispatch
// ------------------------------------------------------------------
constexpr double compute_area(const Shape& s) {
    return s.area();  // Virtual call resolved at compile time!
}

constexpr const char* get_name(const Shape& s) {
    return s.name();
}

// ------------------------------------------------------------------
// 4. constexpr function comparing shapes
// ------------------------------------------------------------------
constexpr bool is_larger(const Shape& a, const Shape& b) {
    return a.area() > b.area();
}

// ------------------------------------------------------------------
// 5. constexpr with polymorphic objects
// ------------------------------------------------------------------
constexpr double total_area() {
    Circle c(5.0);
    Rectangle r(4.0, 6.0);
    Triangle t(3.0, 8.0);

    // Using references for virtual dispatch
    const Shape& s1 = c;
    const Shape& s2 = r;
    const Shape& s3 = t;

    return s1.area() + s2.area() + s3.area();
}

// ------------------------------------------------------------------
// 6. Another hierarchy: Animal
// ------------------------------------------------------------------
class Animal {
public:
    constexpr virtual ~Animal() = default;
    constexpr virtual int legs() const = 0;
    constexpr virtual const char* species() const = 0;
};

class Dog : public Animal {
public:
    constexpr int legs() const override { return 4; }
    constexpr const char* species() const override { return "Dog"; }
};

class Bird : public Animal {
public:
    constexpr int legs() const override { return 2; }
    constexpr const char* species() const override { return "Bird"; }
};

class Spider : public Animal {
public:
    constexpr int legs() const override { return 8; }
    constexpr const char* species() const override { return "Spider"; }
};

constexpr int total_legs() {
    Dog d;
    Bird b;
    Spider s;
    const Animal& a1 = d;
    const Animal& a2 = b;
    const Animal& a3 = s;
    return a1.legs() + a2.legs() + a3.legs();
}

int main()
{
    std::cout << "=== Constexpr Virtual Dispatch ===" << std::endl;
    constexpr Circle c(5.0);
    constexpr Rectangle r(4.0, 6.0);
    constexpr Triangle t(3.0, 8.0);

    constexpr double ca = compute_area(c);
    constexpr double ra = compute_area(r);
    constexpr double ta = compute_area(t);

    std::cout << "  " << get_name(c) << " area: " << ca << std::endl;
    std::cout << "  " << get_name(r) << " area: " << ra << std::endl;
    std::cout << "  " << get_name(t) << " area: " << ta << std::endl;

    std::cout << "\n=== Sides (virtual) ===" << std::endl;
    std::cout << "  " << c.name() << ": " << c.sides() << " sides" << std::endl;
    std::cout << "  " << r.name() << ": " << r.sides() << " sides" << std::endl;
    std::cout << "  " << t.name() << ": " << t.sides() << " sides" << std::endl;

    std::cout << "\n=== Compile-Time Comparison ===" << std::endl;
    constexpr bool c_gt_r = is_larger(c, r);
    constexpr bool r_gt_t = is_larger(r, t);
    std::cout << "  Circle > Rectangle? " << c_gt_r << std::endl;
    std::cout << "  Rectangle > Triangle? " << r_gt_t << std::endl;

    std::cout << "\n=== Total Area (compile-time) ===" << std::endl;
    constexpr double total = total_area();
    std::cout << "  Total: " << total << std::endl;
    static_assert(total > 100.0, "Total area should exceed 100");

    std::cout << "\n=== Animal Hierarchy ===" << std::endl;
    constexpr int legs = total_legs();
    std::cout << "  Dog + Bird + Spider legs: " << legs << std::endl;
    static_assert(legs == 14);
    std::cout << "  static_assert(legs == 14) passed" << std::endl;

    return 0;
}

/*
Expected output:

=== Constexpr Virtual Dispatch ===
  Circle area: 78.5398
  Rectangle area: 24
  Triangle area: 12

=== Sides (virtual) ===
  Circle: 0 sides
  Rectangle: 4 sides
  Triangle: 3 sides

=== Compile-Time Comparison ===
  Circle > Rectangle? 1
  Rectangle > Triangle? 1

=== Total Area (compile-time) ===
  Total: 114.54

=== Animal Hierarchy ===
  Dog + Bird + Spider legs: 14
  static_assert(legs == 14) passed
*/
Run command
g++ -std=c++20 -Wall -Wextra -o example constexpr_virtual.cpp