C ++ 17 Стандартный проект N4659
https://github.com/cplusplus/draft/blob/master/papers/n4659.pdf 6.1 "Объявления и определения" содержит примечание, в котором, вероятно, обобщены все из них:
3 [Примечание: В некоторых случаях реализации C ++ неявно определяют конструктор по умолчанию (15.1), конструктор копирования (15.8), конструктор перемещения (15.8), оператор назначения копирования (15.8), оператор назначения перемещения (15.8),или деструктор (15.4) функций-членов.- конец примечания] [Пример: учитывая
#include <string>
struct C {
std::string s; // std::string is the standard library class (Clause 24)
};
int main() {
C a;
C b = a;
b = a;
}
, реализация будет неявно определять функции, чтобы сделать определение C эквивалентным
struct C {
std::string s;
C() : s() { }
C(const C& x): s(x.s) { }
C(C&& x): s(static_cast<std::string&&>(x.s)) { }
// : s(std::move(x.s)) { }
C& operator=(const C& x) { s = x.s; return *this; }
C& operator=(C&& x) { s = static_cast<std::string&&>(x.s); return *this; }
// { s = std::move(x.s); return *this; }
~ C() { }
};
- конец примера]
Условия, при которых они объявляются, поясняются по адресу: Условия для автоматической генерации ctor по умолчанию / копирования / перемещения и оператора копирования / перемещения?
Отличный способ убедиться, чточто-то имеет значение по умолчанию, чтобы попытаться использовать = default
, как объяснено в: Что означает «значение по умолчанию» после объявления функции класса?
Пример, приведенный ниже, делает это, итакже выполняет все неявно определенные функции.
#include <cassert>
#include <string>
struct Default {
int i;
Default() = default;
Default(const Default&) = default;
Default& operator=(Default&) = default;
Default& operator=(const Default&) = default;
Default(Default&&) = default;
Default& operator=(Default&&) = default;
~Default() = default;
};
struct Instrument {
int i;
static std::string last_call;
Instrument() { last_call = "ctor"; }
Instrument(const Instrument&) { last_call = "copy ctor"; }
Instrument& operator=(Instrument&) { last_call = "copy assign"; return *this; }
Instrument& operator=(const Instrument&) { last_call = "copy assign const"; return *this; }
Instrument(Instrument&&) { last_call = "move ctor"; }
Instrument& operator=(Instrument&&) { last_call = "move assign"; return *this; }
~Instrument() { last_call = "dtor"; }
};
std::string Instrument::last_call;
int main() {
// See what the default constructors are doing.
{
// Default constructor.
Default ctor;
// i is uninitialized.
// std::cout << ctor.i << std::endl;
ctor.i = 1;
// Copy constructor.
Default copy_ctor(ctor);
assert(copy_ctor.i = 1);
// Copy assignment.
Default copy_assign;
copy_assign = ctor;
assert(copy_assign.i = 1);
// Copy assignment const.
const Default const_ctor(ctor);
Default copy_assign_const;
copy_assign_const = const_ctor;
assert(copy_assign_const.i == 1);
// Move constructor.
Default move_ctor(std::move(ctor));
assert(move_ctor.i == 1);
// Move assignment.
Default move_assign;
move_assign = std::move(ctor);
assert(move_assign.i == 1);
}
// Check that the constructors are called by these calls.
{
// Default constructor.
Instrument ctor;
assert(Instrument::last_call == "ctor");
// Copy constructor.
Instrument copy_ctor(ctor);
assert(Instrument::last_call == "copy ctor");
// Copy assignment.
copy_ctor = ctor;
assert(Instrument::last_call == "copy assign");
// Copy assignment const.
const Instrument const_ctor(ctor);
Instrument copy_assign_const;
copy_assign_const = const_ctor;
assert(Instrument::last_call == "copy assign const");
// Move constructor.
Instrument move_ctor(std::move(ctor));
assert(Instrument::last_call == "move ctor");
// Move assignment.
Instrument move_assign;
move_assign = std::move(ctor);
assert(Instrument::last_call == "move assign");
// Destructor.
{
Instrument dtor;
}
assert(Instrument::last_call == "dtor");
}
}
GitHub upstream .
Протестировано с GCC 7.3.0:
g++ -std=c++11 implicitly_defined.cpp