c++ - 使用 CRTP 实现单例
问题描述
阅读此答案后,我尝试实现一些简单的 CRTP 用法。我想我会尝试实现单例(是的,我知道 - 它只是为了练习和研究)模式,因为链接的答案已经做到了......除了它没有编译的事实。
引用的代码如下:
template <class ActualClass>
class Singleton
{
public:
static ActualClass& GetInstance()
{
if(p == nullptr)
p = new ActualClass;
return *p;
}
protected:
static ActualClass* p;
private:
Singleton(){}
Singleton(Singleton const &);
Singleton& operator = (Singleton const &);
};
template <class T>
T* Singleton<T>::p = nullptr;
class A: public Singleton<A>
{
//Rest of functionality for class A
};
然后我将其“现代化”为:
template <class T>
class Singleton {
public:
Singleton() = delete;
Singleton(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator = (const Singleton&) = delete;
Singleton& operator = (Singleton&&) = delete;
static T& get_instance() {
if(!instance)
instance = new T;
return *instance;
}
protected:
static inline T* instance = nullptr;
};
class A: public Singleton<A> {
//Rest of functionality for class A
};
然后我尝试创建对实例的引用:
auto& x = A::get_instance();
这显然没有编译。
值得一提的是,我收到了非常相似的错误消息,特别是:
注意: 'A::A()' 被隐式删除,因为默认定义格式不正确:
class A : public Singleton<A>
。
显然,第二段代码无法编译,因为我们删除了默认构造函数并尝试new T
在get_instance
方法中使用它。
令我惊讶的是,第一个片段也没有编译,并带有类似的错误消息。链接的答案有错误吗?我将如何使用 CRTP为 Singletons 实现通用基类/接口?
解决方案
这是“现代化”片段的修改:
template <class T>
class Singleton {
public:
Singleton& operator = (const Singleton&) = delete;
Singleton& operator = (Singleton&&) = delete;
static T& get_instance() {
if(!instance)
instance = new T_Instance;
return *instance;
}
protected:
Singleton() {}
private:
struct T_Instance : public T {
T_Instance() : T() {}
};
static inline T* instance = nullptr;
};
class A : public Singleton<A> {
protected:
A() {}
};
int main()
{
auto& x = A::get_instance();
}
片段的更改摘要:
protected
单例中的默认构造函数private
嵌套结构访问派生类的受保护构造函数protected
派生类中的构造函数以防止实例化
此外,不需要delete
通过将默认 ctor 实现添加到 Singleton 类来隐式删除的构造函数。
不像Richard Hodges的例子那么小,但是静态instance
成员可以很容易地添加 delete_instance() 方法以用于自动化单元测试。
推荐阅读
- c# - ASP.NET Core 5 WebAPI - Azure AD - 使用 Azure 广告访问令牌调用图形 API
- ios - CloudKit 未按预期运行以存储文档
- json - 如何在 Ansible 中使用较小的 JSON 子集更新现有 JSON?
- node.js - 在nodejs中使用axios的Ldap连接不起作用
- avx2 - 我可以在介子“编译”测试中添加额外的标志吗?
- google-maps - 如何将谷歌地图位置添加到我的网站
- c# - 使用 LINQ 在 DBSet 中选择具有特定属性的 EF 属性
- selenium - 如何使用 selenium python 从 yelp 中提取数据
- html - 如何从 Angular 的列表中打印搜索值
- javascript - 如何为数组中的每个对象生成多张卡片?