Недавно я наткнулся на этот ответ, в котором описывается, как инициализировать std::array
элементов, не соответствующих стандарту. Я не был так удивлен, потому что этот ответ явно не делает никаких построений по умолчанию.
Вместо этого он создает временный std::array
с использованием агрегатной инициализации, затем перемещается (если доступен конструктор перемещения) или копируется в именованную переменную, когда функция возвращается. Поэтому нам нужен только конструктор перемещения или конструктор копирования.
Или так я думал...
Затем пришел этот фрагмент кода, который меня смутил:
struct foo {
int x;
foo(int x) : x(x) {}
foo() = delete;
foo(const foo&) = delete;
foo& operator=(const foo&) = delete;
foo(foo&&) = delete;
foo& operator=(foo&&) = delete;
};
foo make_foo(int x) {
return foo(x);
}
int main() {
foo f = make_foo(1);
foo g(make_foo(2));
}
Все пять специальных конструкторов/операторов специального элемента явно удалены, поэтому теперь я не смог бы построить свой объект из возвращаемого значения, правильно?
Неправильно.
К моему удивлению, это компилируется в gcc (с С++ 17)!
Почему это компилируется? Очевидно, чтобы вернуть foo
из функции make_foo()
, мы должны построить foo
. Это означает, что в функции main()
мы присваиваем или создаем foo
из возвращаемого foo
. Как это возможно?!