我在类中的函数声明旁边看过default
。它做了什么?
class C {
C(const C&) = default;
C(C&&) = default;
C& operator=(const C&) & = default;
C& operator=(C&&) & = default;
virtual ~C() { }
};
答案 0 :(得分:221)
这意味着您要使用该函数的编译器生成版本,因此您无需指定正文。
您还可以使用= delete
指定您不希望编译器自动生成该功能。
随着移动构造函数和移动赋值运算符的引入,生成构造函数,析构函数和赋值运算符的自动版本的规则变得非常复杂。使用= default
和= delete
可以让您更轻松,因为您不需要记住规则:您只需说出您想要发生的事情。
答案 1 :(得分:41)
这是一个新的C ++ 0x功能,它告诉编译器创建相应构造函数或赋值运算符的默认版本,即只为每个成员执行复制或移动操作的版本。这很有用,因为移动构造函数并不总是默认生成(例如,如果你有一个自定义析构函数),不像复制构造函数(同样适用于赋值),但是如果没有什么不值得写的,最好让它编译器处理它而不是每次拼出它。
另请注意,如果提供任何其他非默认构造函数,则不会生成默认构造函数。如果您仍然需要默认构造函数,则可以使用此语法让编译器创建一个。
作为另一个用例,有几种情况下不会隐式生成复制构造函数(例如,如果您提供自定义移动构造函数)。如果您仍然需要默认版本,可以使用此语法请求它。
有关详细信息,请参阅标准的第12.8节。
答案 2 :(得分:20)
它是C ++ 11中的新功能,请参阅here。如果您定义了一个构造函数,但想要为其他构造函数使用默认值,那么它会非常有用。一旦你定义了构造函数,你必须定义所有构造函数,即使它们等同于默认构造函数。
另请注意,在某些情况下,无法提供用户定义的默认构造函数,其行为与在默认和值初始化下合成的编译器相同。 default
允许您恢复该行为。
答案 3 :(得分:11)
我在这些答案中没有提到的另一个用例是它很容易让你改变构造函数的可见性。例如,您可能希望朋友类能够访问复制构造函数,但您不希望它公开可用。
答案 4 :(得分:0)
C ++ 17 N4659标准草案
https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2“显式默认函数”:
1形式的函数定义:
attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ;
被称为显式默认定义。明确默认的功能应
(1.1)—是一个特殊的成员函数,
(1.2)—具有相同的声明函数类型(除了可能不同的ref限定符,以及在 如果是复制构造函数或复制赋值运算符,则参数类型可以是“对 非常量T”,其中T是成员函数的类的名称),就好像它已隐式声明一样, 和
(1.3)-没有默认参数。
2未定义为删除的显式默认函数只有在以下情况下才可以声明为constexpr: 已隐式声明为constexpr。如果一个函数在其第一个声明中被明确默认为默认值,则为 如果隐式声明是,则隐式认为是constexpr。
3如果显式默认的函数是使用noexcept-specifier声明的,而noexcept-specifier不会产生相同的结果 异常说明作为隐式声明(18.4),然后
(3.1)—如果该函数在其第一个声明中被显式默认,则定义为已删除;
(3.2)—否则,程序格式错误。
4 [示例:
struct S { constexpr S() = default; // ill-formed: implicit S() is not constexpr S(int a = 0) = default; // ill-formed: default argument void operator=(const S&) = default; // ill-formed: non-matching return type ~ S() noexcept(false) = default; // deleted: exception specification does not match private: int i; // OK: private copy constructor S(S&); }; S::S(S&) = default; // OK: defines copy constructor
—结束示例]
5显式默认函数和隐式声明函数统称为默认函数,并且 实现应为其提供隐式定义(15.1 15.4、15.8),这可能意味着 他们被删除。如果函数是由用户声明的,并且未明确指定为默认值或已删除,则由用户提供 在它的第一个声明中。用户提供的显式默认功能(即在第一个函数后显式默认的功能) 声明)定义在显式默认的位置;如果此类函数隐式定义为 删除后,程序格式不正确。 [注意:在第一个声明后将函数声明为默认函数可以 提供有效的执行和简明的定义,同时为不断发展的代码提供稳定的二进制接口 基础。 —尾注]
6 [示例:
struct trivial { trivial() = default; trivial(const trivial&) = default; trivial(trivial&&) = default; trivial& operator=(const trivial&) = default; trivial& operator=(trivial&&) = default; ~ trivial() = default; }; struct nontrivial1 { nontrivial1(); }; nontrivial1::nontrivial1() = default; // not first declaration
—结束示例]
然后,问题当然是可以隐式声明哪些函数以及何时进行隐式声明,这已在以下内容中进行了解释: