Reputation: 23527
I am trying to use CRTP to register all live (created but not yet destroyed) instances of some class. This works for me well:
template <typename T>
class Registrable {
public:
void _register(T* p) { instances_.insert(p); }
void _unregister(T* p) { instances_.erase(instances_.find(p)); }
static const std::set<T*> & instances() { return instances_; }
private:
static std::set<T*> instances_;
};
template <typename T>
std::set<T*> Registrable<T>::instances_;
class Class : private Registrable<Class> {
public:
using Registrable<Class>::instances;
Class() { _register(this); }
Class(const Class &) { _register(this); }
Class(Class &&) { _register(this); }
~Class() { _unregister(this); }
void function() { }
};
int main() {
Class c;
auto upc = std::make_unique<Class>(c);
std::vector<Class> vc(5);
for (auto i : Class::instances())
i->function();
}
EDITED:
Better would be not to care about registering and unregistering of instances in derived classes. Solution according to @Jean-BaptisteYunès and @Aconcagua:
template <typename T>
class Registrable {
public:
static const std::set<T*> & instances() { return instances_; }
protected:
Registrable() { instances_.insert(static_cast<T*>(this)); }
Registrable(const Registrable &) : Registrable() { }
Registrable(Registrable &&) : Registrable() { }
~Registrable() { instances_.erase(instances_.find(static_cast<T*>(this))); }
private:
static std::set<T*> instances_;
};
...
class Class : public Registrable<Class> { ... }
However, I am also not sure whether this type of casting is safe. Especially, if Class
would additionally derive from another class via multiple inheritance.
The answer of @amc176 claims, that I can assume that the cast will be successful, but I would prefer to be sure. According to @Aconcagua's comment, I can be sure, just it's not in the answer.
Upvotes: 3
Views: 522
Reputation: 1544
static_cast
makes no runtime checks to ensure the cast is completely safe. Anyway, as you know the type T
will be a derived class of Registrable<T>
, you can assume the cast will be successful.
In fact, in cppreference it's mentioned that this cast is typically used when applying CRTP (referred as static polymorphism
in the link).
Upvotes: 2