对于了解 =default 和 =delete 的人来说,意图是非常清楚的。你不必了解用于自动生成特殊成员函数的规则。
对于创建不可移动、只能动态分配或无法动态分配的用户定义类型,存在类似惯例。所有这些惯例都具有 C++11 之前的实现,这些实现会遭受类似问题,并且可在 C++11 中通过按照默认和已删除特殊成员函数实现它们,以类似方式进行解决。
显式默认设置的函数
可以默认设置任何特殊成员函数 — 以显式声明特殊成员函数使用默认实现、定义具有非公共访问限定符的特殊成员函数或恢复其他情况下被阻止其自动生成的特殊成员函数。
可通过如此示例所示进行声明来默认设置特殊成员函数:
struct widget
{
widget()=default;
inline widget& operator=(const widget&);
};
inline widget& widget::operator=(const widget&) =default;
请注意,只要特殊成员函数可内联,便可以在类主体外部默认设置它。
由于普通特殊成员函数的性能优势,因此我们建议你在需要默认行为时首选自动生成的特殊成员函数而不是空函数体。你可以通过显式默认设置特殊成员函数,或通过不声明它(也不声明其他会阻止它自动生成的特殊成员函数),来实现此目的。
注意
Visual Studio 不支持默认的移动构造函数或移动赋值运算符作为 C++11 标准授权。有关详细信息,请参阅 支持 C++11/14/17 功能(现代 C++)中的“默认函数和已删除的函数”一节。
已删除的函数
可以删除特殊成员函数以及普通成员函数和非成员函数,以阻止定义或调用它们。通过删除特殊成员函数,可以更简洁地阻止编译器生成不需要的特殊成员函数。必须在声明函数时将其删除;不能在这之后通过声明一个函数然后不再使用的方式来将其删除。
struct widget
{
// deleted operator new prevents widget from being dynamically allocated.
void* operator new(std::size_t) = delete;
};
删除普通成员函数或非成员函数可阻止有问题的类型提升导致调用意外函数。这可发挥作用的原因是,已删除的函数仍参与重载决策,并提供比提升类型之后可能调用的函数更好的匹配。函数调用将解析为更具体的但可删除的函数,并会导致编译器错误。
// deleted overload prevents call through type promotion of float to double from succeeding.
void call_with_true_double_only(float) =delete;
void call_with_true_double_only(double param) { return; }
请注意,在前面的示例中,使用 call_with_true_double_only 参数调用 float 将导致编译器错误,但使用 call_with_true_double_only 参数调用 int 不会导致编译器错误;在 int 示例中,此参数将从 int 提升到 double,并成功调用函数的 double 版本,即使这可能并不是预期目的。若要确保使用非双精度参数对此函数进行的任何调用均会导致编译器错误,您可以声明已删除的函数的模板版本。










