我们先讲众所周知的基本概念,再讲点别的
弃置函数
如果使用特殊语法
= delete ;
取代函数体,那么该函数被定义为弃置的(deleted)。任何弃置函数的使用都是非良构的(程序无法编译)。这包含调用,包括显式(以函数调用运算符)及隐式(对弃置的重载运算符、特殊成员函数、分配函数等的调用),构成指向弃置函数的指针或成员指针,甚至是在不求值表达式中使用弃置函数。但是可以隐式 ODR 使用刚好被弃置的非纯虚成员函数。如果函数被重载,那么首先进行重载决议,且只有在选择了弃置函数时程序才非良构:
struct sometype { void* operator new(std::size_t) = delete; void* operator new[](std::size_t) = delete; }; sometype* p = new sometype; // 错误:尝试调用弃置的 sometype::operator new函数的弃置定义必须是翻译单元中的首条声明:已经声明过的函数不能声明为弃置的:
struct sometype { sometype(); }; sometype::sometype() = delete; // 错误:必须在首条声明弃置由用户提供的函数
如果一个函数由用户声明且没有在它的首个声明被显式预置或显式弃置,那么它由用户提供。由用户提供的显式预置的函数(即在它的首个声明后被显式预置)在它被显式预置的地方定义;如果该函数被隐式定义为弃置的,那么程序非良构。需要为不断变化的代码库提供稳定的二进制接口的情况下,在函数的首个定义后再声明为预置可以保证执行效率,也能提供简明的定义。
// trivial 的所有特殊成员函数都分别在它们的首个声明处被显式预置, // 因此它们都不由用户提供 struct trivial { trivial() = default; trivial(const trivial&) = default; trivial(trivial&&) = default; trivial& operator=(const trivial&) = default; trivial& operator=(trivial&&) = default; ~trivial() = default; }; struct nontrivial { nontrivial(); // 首个声明 }; // 没有在首个声明处被显式预置, // 因此该函数由用户提供并在此定义 nontrivial::nontrivial() = default;
直接看代码
#include struct Test { void a(double x) {} void a(int x) = delete; template<class T> void f(T c){} template<> void f(int c) = delete; }; void a(double x) {} void a(int x) = delete; int main() { //Test().a(10);//error Test().a(10.0); //Test().f(10);//error Test().f(10.0); //a(10)//error a(10.0); }这种写法很有趣且简洁,要比C++20约束之类的去除单个类型更加直观,且还能作用于全局函数,成员函数重载的情况,与模板特例化的情况
我可以说,这C++11的语法,几乎没有什么书会介绍这种写法,它非常好用且简洁
我们分别举例的是成员函数,模板特例化,全局函数