我在类中看到过在函数声明旁边使用默认值。它能做什么?

class C {
  C(const C&) = default;
  C(C&&) = default;
  C& operator=(const C&) & = default;
  C& operator=(C&&) & = default;
  virtual ~C() { }
};

当前回答

这是c++ 11的一个新特性。

这意味着您希望使用该函数的编译器生成版本,因此不需要指定函数体。

您还可以使用= delete指定不希望编译器自动生成该函数。

随着move构造函数和move赋值操作符的引入,何时生成构造函数、析构函数和赋值操作符的自动版本的规则变得相当复杂。使用= default和= delete使事情变得更简单,因为您不需要记住规则:您只需说出您希望发生什么。

其他回答

This is a new C++0x feature that tells the compiler to create the default version of the respective constructor or assignment operator, i.e. the one which just performs the copy or move action for each member. This is useful because the move constructor isn't always generated by default (e.g. if you have a custom destructor), unlike the copy constructor (and likewise for assignment), but if there's nothing non-trivial to write, it's better to let the compiler handle it than to spell it out yourself each time.

还要注意,如果您提供任何其他非默认构造函数,则不会生成默认构造函数。如果仍然需要默认构造函数,可以使用此语法让编译器创建一个默认构造函数。

作为另一个用例,有几种情况下,复制构造函数不会隐式生成(例如,如果你提供了一个自定义的移动构造函数)。如果仍然需要默认版本,可以使用以下语法请求它。

详见标准的12.8节。

我在这些回答中没有看到的另一个用例是,它允许您轻松地更改构造函数的可见性。例如,也许您希望友类能够访问复制构造函数,但又不希望它是公开可用的。

它是c++ 11中的新功能,请参见这里。如果您已经定义了一个构造函数,但希望对其他构造函数使用默认值,那么它可能非常有用。在c++ 11之前,一旦定义了一个构造函数,就必须定义所有的构造函数,即使它们等同于默认值。

还要注意,在某些情况下,不可能提供一个用户定义的默认构造函数,其行为与编译器在默认和值初始化时合成的构造函数相同。默认允许您恢复该行为。

c++ 17 N4659标准草案

https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 11.4.2“显式默认函数”:

1 A function definition of the form: attribute-specifier-seq opt decl-specifier-seq opt declarator virt-specifier-seq opt = default ; is called an explicitly-defaulted definition. A function that is explicitly defaulted shall (1.1) — be a special member function, (1.2) — have the same declared function type (except for possibly differing ref-qualifiers and except that in the case of a copy constructor or copy assignment operator, the parameter type may be “reference to non-const T”, where T is the name of the member function’s class) as if it had been implicitly declared, and (1.3) — not have default arguments. 2 An explicitly-defaulted function that is not defined as deleted may be declared constexpr only if it would have been implicitly declared as constexpr. If a function is explicitly defaulted on its first declaration, it is implicitly considered to be constexpr if the implicit declaration would be. 3 If a function that is explicitly defaulted is declared with a noexcept-specifier that does not produce the same exception specification as the implicit declaration (18.4), then (3.1) — if the function is explicitly defaulted on its first declaration, it is defined as deleted; (3.2) — otherwise, the program is ill-formed. 4 [ Example: 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 — end example ] 5 Explicitly-defaulted functions and implicitly-declared functions are collectively called defaulted functions, and the implementation shall provide implicit definitions for them (15.1 15.4, 15.8), which might mean defining them as deleted. A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first declaration) is defined at the point where it is explicitly defaulted; if such a function is implicitly defined as deleted, the program is ill-formed. [ Note: Declaring a function as defaulted after its first declaration can provide efficient execution and concise definition while enabling a stable binary interface to an evolving code base. — end note ] 6 [ Example: 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 — end example ]

接下来的问题当然是哪些函数可以隐式声明以及何时会发生,我已经在以下部分解释过:

c++中的<=>("太空船",三向比较)操作符是什么? 编译器为类创建的所有成员函数是什么?这种情况经常发生吗? 自动生成默认/复制/移动变量和复制/移动赋值操作符的条件?

这是c++ 11的一个新特性。

这意味着您希望使用该函数的编译器生成版本,因此不需要指定函数体。

您还可以使用= delete指定不希望编译器自动生成该函数。

随着move构造函数和move赋值操作符的引入,何时生成构造函数、析构函数和赋值操作符的自动版本的规则变得相当复杂。使用= default和= delete使事情变得更简单,因为您不需要记住规则:您只需说出您希望发生什么。