Search code examples
c++templatespolymorphismc++-templates

Is Compile-time Polymorphism in C++ Templates Possible?


Consider the following code snippet:

#include <iostream>
#include <typeinfo>


template<typename T>
class TypePrinter{
    public:
    void print_type() {
        std::cout << typeid(T).name() << std::endl;
    }
}; // end class TypePrinter


class Base{
    public:
    TypePrinter<Base> createTypePrinter(){ // TODO replace "Base" with the class of the instance.
        return TypePrinter<Base>();
    }
}; // end Base

class Derived: public Base{
};

int main() {
    // Create a derived instance and try to create a TypePrinter for it
    Derived d;
    auto tp = d.createTypePrinter();
    tp.print_type(); // prints "4Base".
    return 0;
} // end main

In the example above, I have

  • a class with a typename template parameter (TypePrinter) and
  • another class that instantiate it, using its type as a parameter (Base)

How can the code above be rewritten so that the inherited derived_instance.createTypePrinter() method can create a TypePrinter<Derived> rather than a TypePrinter<Base>?

In other words, what modifications could allow d.createTypePrinter().print_type() to print "Derived"?


Solution

  • As noted in the comments, this can be implemented with the Curiously Recurring Template Pattern.

    #include <iostream>
    #include <typeinfo>
    
    
    template<typename T>
    class TypePrinter{
        public:
        void print_type() {
            std::cout << typeid(T).name() << std::endl;
        }
    }; // end class TypePrinter
    
    template<typename T> // Base is now a template class. 
                         // Subclasses set T to their type
    class Base{
        public:
        TypePrinter<T> createTypePrinter(){
            return TypePrinter<T>();
        }
    }; // end Base
    
    class Derived: public Base<Derived>{
    };
    
    int main() {
        // Create a derived instance and try to create a TypePrinter for it
        Derived d;
        auto tp = d.createTypePrinter();
        tp.print_type(); // Now this prints "7Derived"
        return 0;
    } // end main