c++ - 在 CRTP 的基类中使用 `this` 作为指向派生类的指针

标签 c++ this crtp

我正在尝试使用 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> 的派生类,您可以假设转换会成功。

事实上,在cppreference提到此转换通常在应用 CRTP 时使用(在链接中称为 static polymorphism )。

关于c++ - 在 CRTP 的基类中使用 `this` 作为指向派生类的指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48417855/

相关文章:

c++ - 函数模板作为参数

c++ - 替代长 switch 语句

javascript - 回复 : A JavaScript Fn that accepts unknown # args - call Fn wrks - call via var does not

JavaScript。从立即调用函数获取外部对象的引用

Jquery - 将 $(this) 传递给不带 var 的回调函数

c++ - 带有破坏操作的侵入式引用计数

C++ 网络套接字、SCTP 和数据包大小

c++ - 读+写和读+写+截断有什么区别?

c++ - CRTP - 静态接口(interface)中的 "abstract"方法

c++ - 继承和CRTP