#include <iostream>
#include <string>
using namespace std;
// Utility class, mostly.
// The secret sauce is static_cast.
// as_subclass() is there only to help deduce when to const things.
template <typename TSubclass>
class crtp_template {
protected:
using subclass_type = TSubclass;
subclass_type& as_subclass() { return static_cast<subclass_type&>(*this); }
subclass_type const& as_subclass() const { return static_cast<subclass_type const&>(*this); }
};
// Here we have a base class. A compile-time template.
// It may depend on some subclass methods to do its job.
template <typename TSubclass>
class entity_template : public crtp_template<TSubclass> {
public:
void greet() { std::cout << this->as_subclass().make_greet() << std::endl; }
};
class entity : public entity_template<entity> {
public:
friend class entity_template<entity>;
entity(std::string name) : name_(name) {}
private:
std::string make_greet() {
using namespace std::literals;
return "Hello, "s + this->name_ + "!";
}
private:
std::string name_ = "there";
};
int main() {
using namespace std::literals;
entity world("world"s);
world.greet();
return 0;
}