使用 'this' 作为指向 CRTP 基类中派生类的指针

Using `this` as a pointer to derived class in a base class in CRTP

本文关键字:派生 指针 基类 this 使用 CRTP      更新时间:2023-10-16

我正在尝试使用 CRTP 注册某个类的所有实时(已创建但尚未销毁(实例。这对我很有用:

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();
}

编辑:

最好不要关心在派生类中注册和注销实例。根据@Jean-BaptisteYunès和@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> { ... }

但是,我也不确定这种类型的铸造是否安全。特别是,如果Class通过多重继承从另一个类派生。

@amc176的答案是,我可以假设演员阵容会成功,但我更愿意确定。根据@Aconcagua的评论,我可以肯定,只是它不在答案中。

static_cast不进行运行时检查以确保强制转换完全安全。无论如何,如您所知,T类型将是Registrable<T>的派生类,您可以假设强制转换会成功。

事实上,在 cpp首选项中提到,此强制转换通常在应用 CRTP(在链接中称为 static polymorphism(时使用。