不可通过删除析构函数实现class?
Non instatiable class by deleting destructor?
我有一个 class
纯粹用于语法目的,以某种方式调用函数。这是一个简化的例子:
#include<iostream>
template<class T1>
struct make{
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
};
int main(){
double d = make<double>::from(2);
std::cout << d << '\n';
}
现在,假设我想警告用户不应实例化此 class。 class 可能有一些用途,但是
我很好奇是否可以禁止这样做?
首先我尝试删除默认构造函数
template<class T1>
struct make{
make() = delete;
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
};
但是这仍然是可能的:
make<double> m{}; // valid
最后,我尝试删除析构函数,这似乎奏效了
template<class T1>
struct make{
~make() = delete;
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
};
不过看来class还是可以被new
分配的。
我是否应该同时删除析构函数和删除构造函数,(复制和移动构造函数呢?)
这是禁止实例化的最佳方式吗?
代码在这里:http://coliru.stacked-crooked.com/a/0299c377c129fffb
#include<iostream>
template<class T1>
struct make{
make() = delete;
~make() = delete;
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
};
int main(){
double d = make<double>::from(2);
std::cout << d << '\n';
make<double> m{}; // compile error (no destructor)
auto p = new make<double>{}; // compile error (no constructor)
}
But then this is still possible:
make<double> m{}; // valid
...我不知道那行得通。但既然我这样做了,我也知道 为什么 它有效。因此,如何阻止它。
之所以有效,是因为 make<T>
正如您声明的那样,它是一个集合。即使它有一个删除的默认构造函数,C++ 仍然认为它是一个聚合。如果你在聚合上使用 braced-init-lists,你会得到 aggregate initialization.
停止它的方法很简单:让它不再是聚合:
template<class T1>
struct make{
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
make() = delete;
private:
char c; //Not an aggregate
};
该私有成员强制 make<T>
不再是聚合。因此,它不能与聚合初始化一起使用,因此 {}
将尝试调用默认构造函数。这自然会失败,因为它被删除了。
可简单复制的技巧仍可用于创建 make<T>
的实例。您可以通过给它一个 virtual
析构函数来关闭它们:
template<class T1>
struct make{
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
make() = delete;
private:
char c; //Not an aggregate
virtual ~make() = default;
};
这应该足以防止合法的 C++ 代码创建该类型的对象。
我有一个 class
纯粹用于语法目的,以某种方式调用函数。这是一个简化的例子:
#include<iostream>
template<class T1>
struct make{
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
};
int main(){
double d = make<double>::from(2);
std::cout << d << '\n';
}
现在,假设我想警告用户不应实例化此 class。 class 可能有一些用途,但是 我很好奇是否可以禁止这样做?
首先我尝试删除默认构造函数
template<class T1>
struct make{
make() = delete;
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
};
但是这仍然是可能的:
make<double> m{}; // valid
最后,我尝试删除析构函数,这似乎奏效了
template<class T1>
struct make{
~make() = delete;
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
};
不过看来class还是可以被new
分配的。
我是否应该同时删除析构函数和删除构造函数,(复制和移动构造函数呢?)
这是禁止实例化的最佳方式吗? 代码在这里:http://coliru.stacked-crooked.com/a/0299c377c129fffb
#include<iostream>
template<class T1>
struct make{
make() = delete;
~make() = delete;
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
};
int main(){
double d = make<double>::from(2);
std::cout << d << '\n';
make<double> m{}; // compile error (no destructor)
auto p = new make<double>{}; // compile error (no constructor)
}
But then this is still possible:
make<double> m{}; // valid
...我不知道那行得通。但既然我这样做了,我也知道 为什么 它有效。因此,如何阻止它。
之所以有效,是因为 make<T>
正如您声明的那样,它是一个集合。即使它有一个删除的默认构造函数,C++ 仍然认为它是一个聚合。如果你在聚合上使用 braced-init-lists,你会得到 aggregate initialization.
停止它的方法很简单:让它不再是聚合:
template<class T1>
struct make{
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
make() = delete;
private:
char c; //Not an aggregate
};
该私有成员强制 make<T>
不再是聚合。因此,它不能与聚合初始化一起使用,因此 {}
将尝试调用默认构造函数。这自然会失败,因为它被删除了。
可简单复制的技巧仍可用于创建 make<T>
的实例。您可以通过给它一个 virtual
析构函数来关闭它们:
template<class T1>
struct make{
template<class T2>
static T1 from(T2 const& t2){
return T1{}; //or something more complicated
}
make() = delete;
private:
char c; //Not an aggregate
virtual ~make() = default;
};
这应该足以防止合法的 C++ 代码创建该类型的对象。