There are 2 main methods demoed here;
- A template constructor with pointer approach called "AutoIDPtr" which is what you want if your classes have many layers of inheritance like the "CChild" example
- A CRTP Mixin approach call "AutoIDMixin" is also possible and cuts out the mess on the stack at runtime, BUT this prevents any more derivation on the class. It also means that you have to keep typing out the instantiated class name in all the constructors as well which gets annoying.
- A final way that is not shown is to use pass down a summary of results in a AutoIDBase class and not derive from the AutoID.. classes at all.
#include <iostream> #include <iomanip> #include <stdint.h> #include <typeinfo> #include <functional> #include <map> /**************************************************************** ****************OPTIONAL INFO GATHERING PLACE******************* ****************************************************************/ struct ClassDictionary { struct Reg { uint32_t id_; std::string name_; uint32_t hash_; }; typedef std::map<std::string, Reg> RegMap; template <typename T> static uint32_t reg() { std::string key = typeid(T).name(); uint32_t hash = std::hash<std::string>()(typeid(T).name()); std::cout << "Registering hash:" << std::hex << std::setw(8) << hash << std::dec << " as " << key << "\n"; return regCore(key,hash); } static uint32_t regCore(std::string key, uint32_t hash) { RegMap::iterator rit = regMap_.find(key); if (rit != regMap_.end()) return rit->second.hash_; regMap_[key].id_ = gID++; regMap_[key].name_ = key; regMap_[key].hash_ = hash; return regMap_[key].hash_; } static void printList() { std::cout << "ClassDictionary has " << gID << " entries\n"; for (const auto& e : regMap_ ) { std::cout << "Entry:" << e.second.id_ << " Hash:" << std::hex << std::setw(8) << e.second.hash_ << std::dec << " Name:" << e.second.name_ << "\n"; } } static uint32_t gID; static RegMap regMap_; }; uint32_t ClassDictionary::gID = 0; ClassDictionary::RegMap ClassDictionary::regMap_; /**************************************************************** ***************************THE CORE***************************** ****************************************************************/ template <typename T> struct Attrib { static const uint32_t REG_ID; static const char* NAME; static const uint32_t ID; enum { SIZE = sizeof(T) } ; }; template<typename T> const char* Attrib<T>::NAME = typeid(T).name(); template<typename T> const unsigned Attrib<T>::ID = std::hash<std::string>()(typeid(T).name()); template<typename T> const uint32_t Attrib<T>::REG_ID = ClassDictionary::reg<T>(); class Base { public: Base(uint32_t type, uint32_t size) : type_(type), size_(size) {} void whoami() { std::cout << "I am type:" << std::hex << std::setw(8) << type_ << std::dec << " size:" << size_ << "\n"; } private: uint32_t type_; uint32_t size_; }; class AutoIdPtr : public Base { public: template <typename T> AutoIdPtr(T* kid) : Base(Attrib<T>::REG_ID, Attrib<T>::SIZE) {} }; template <typename T> class AutoIdMixin : public Base { public: AutoIdMixin() : Base(Attrib<T>::REG_ID, Attrib<T>::SIZE) {} }; /**************************************************************** ***************************TEST IT****************************** ****************************************************************/ class A : public AutoIdMixin<A> { public: A() : AutoIdMixin<A>() {} }; class B : public AutoIdPtr { public: B() : AutoIdPtr(this) {} int var; }; class C : public AutoIdPtr { public: C() : AutoIdPtr(this) {} template <typename T> C(T* child) : AutoIdPtr(child) {} char stuff[10]; }; class CChild : public C { CChild() : C(this) {} }; class IHaveALongAndMessyName : public AutoIdPtr { public: IHaveALongAndMessyName() : AutoIdPtr(this) {} }; int main() { A a; B b; C c; C c2; a.whoami(); b.whoami(); c.whoami(); ClassDictionary::printList(); }The output looks like
Registering hash:85b5dc34 as 1A Registering hash:60a08ea3 as 1B Registering hash:d9107b5c as 1C Registering hash:59e2da5b as 22IHaveALongAndMessyName Registering hash:52593138 as 6CChild I am type:85b5dc34 size:8 I am type:60a08ea3 size:12 I am type:d9107b5c size:20 ClassDictionary has 5 entries Entry:0 Hash:85b5dc34 Name:1A Entry:1 Hash:60a08ea3 Name:1B Entry:2 Hash:d9107b5c Name:1C Entry:3 Hash:59e2da5b Name:22IHaveALongAndMessyName Entry:4 Hash:52593138 Name:6CChild
No comments:
Post a Comment