Копирование и перемещение элементов списка инициализации

#include <iostream>

struct A {
    A() { std::cout << 1; }
    A(const A&) { std::cout << 2; }
    A(A&&) { std::cout << 3; }
};

void foo(auto l) {}

int main() {
    auto l = {A{}};
    foo(l);
    foo(std::move(l));
}

Почему программа печатает 1, а не 123 или другую комбинацию? Какие конструкторы вызываются и почему?


Ответы (1 шт):

Автор решения: KoVadim

Если закрыть глаза на то, что clang не компилирует, а gcc - да, но с ворнингами, то на самом деле можно считать, что функция foo выглядит так

template<typename T>
void foo(T l) {}

(мы же знаем, что в большинстве случаев для auto способ вывода типов подобен шаблонному, поэтому, такая замена допустима).

Осталось выяснить, а какой же тип у l? А тут не все так очевидно. Он там std::initializer_list<A>. И при инициализации единственного его аргумента и вызывается конструктор по умолчанию.

Теперь можно понять и настоящую сигнатуру функции foo

void foo<std::initializer_list<A> >(std::initializer_list<A>)

(взято с недр ассемблерного кода, который сгенерировал gcc) и эта сигнатура соответствует тому, что и ожидалось вначале.

Теперь смотрим в документацию https://en.cppreference.com/w/cpp/utility/initializer_list

Initializer lists may be implemented as a pair of pointers or pointer and length. Copying a std::initializer_list does not copy the underlying objects.

и выделенное будет ответом.

→ Ссылка