用=delete替代private作用域来禁用函数

C++11 之前禁用拷贝的方式是将拷贝构造函数和拷贝赋值运算符声明在 private 作用域中:

class A {
private:
    A(const A&); // 不需要定义
    A& operator=(const A&);
};

C++11 中可以直接将要删除的函数用 =delete 声明,习惯上会声明在 public 作用域中,这样在使用删除的函数时,会先检查访问权再检查删除状态,出错时能得到更明确的诊断信息。

class A {
public:
    A(const A&) = delete;
    A& operator(const A&) = delete;
};

private 作用域中的函数还可以被成员和友元调用,而 =delete 是真正禁用了函数,无法通过任何方法调用。

任何函数都可以用 =delete 声明,比如函数不想接受某种类型的参数,就可以删除对应类型的重载。

void f(int);
void f(double) = delete; //@ 拒绝double和float类型参数
f(3.14); //@ 错误

=delete 还可以禁止模板对某个类型的实例化:

template<typename T>
void f(T x) {}

template<>
void f<int>(int) = delete;

f(1); //@ 错误:使用已删除的函数
template<typename T>
void processPointer(T * ptr);

类内的函数模板也可以用这种方式禁用:

class A {
public:
template<typename T>
	void f(T x) {}
};

template<>
void A::f<int>(int) = delete;

当然,写在 private 作用域也可以起到禁用的效果:

class A {
public:
    template<typename T>
    void f(T x) {}
private:
    template<>
    void f<int>(int);
};

但把模板和特化置于不同的作用域不太合逻辑,与其效仿 =delete 的效果,不如直接用 =delete