-1

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

  • 1
    several possibility according to what your ultimate goal is. First I would propose CRTP (a random [link](https://subscription.packtpub.com/book/programming/9781788832564/8/ch08lvl1sec59/crtp-and-static-polymorphism) on the subject). In your specific example, it looks like a factory pattern: no need for fancy design, return smart-pointer to base and ```createTypePrinter``` may be virtual. – Oersted Jun 02 '23 at 15:10
  • 1
    [CRTP](https://stackoverflow.com/questions/4173254/what-is-the-curiously-recurring-template-pattern-crtp) is a well known pattern in C++, yes? It's usually different from _Generics_ used in other languages like C#, Delphi, or Java. – πάντα ῥεῖ Jun 02 '23 at 15:11
  • 3
    You might be interested in the [curiously recurring template pattern](https://en.cppreference.com/w/cpp/language/crtp), in which a base class receives its own derived class as a template argument and is therefore able to use that information to do things like instantiate a `TypePrinter`. [Demo here](https://godbolt.org/z/sz7P1Y8EE) – Nathan Pierson Jun 02 '23 at 15:13
  • 1
    @NathanPierson I tend to believe this question is a duplicate of the CRTP stuff. Just an unexperienced, uninformed user. – πάντα ῥεῖ Jun 02 '23 at 15:15
  • 1
    C++ templates are using duck typing so yes. CRTP is not required. – Marek R Jun 02 '23 at 15:17
  • 1
    Yep, you all are right. This can be implemented with the CTRP. I guess that really does make me "just an unexperienced, uninformed user" – NullPointerException Jun 02 '23 at 15:29
  • 2
    @NullPointerException Well, please note, that wasn't meant to diminish you in any way. I actually believe, that the linked stuff should help you to resolve your doubts/misconceptions. No offense ... – πάντα ῥεῖ Jun 02 '23 at 15:46
  • No offense taken; thank you for taking the time to help! – NullPointerException Jun 02 '23 at 16:00

1 Answers1

2

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