Копирование и перемещение в инициализации std :: pair - PullRequest
3 голосов
/ 11 апреля 2020

У меня есть следующий код и его вывод напечатан ниже. Я не могу понять, почему один набор фигурной инициализации приводит к вызову конструктора перемещения, а другой - к конструктору копирования. Я несколько сузил его до прямой инициализации списков по сравнению с инициализацией списков копий для https://en.cppreference.com/w/cpp/language/list_initialization Я просто не могу понять, к какому случаю относится мой код. Заранее спасибо.

#include <cstdint>
#include <iostream>
using namespace std;

struct Foo {
  Foo() {
    cout << "create foo\n";
  }

  ~Foo() {
    cout << "delete foo\n";
  }

  Foo(const Foo& f) {
    cout << "copy foo\n";
  }

  Foo(Foo&& f) noexcept {
    cout << "move foo\n";
  }

  Foo& operator=(const Foo& f) = delete;

  Foo& operator=(Foo&& f) = delete;
};

int32_t main() {
  pair<uint32_t, Foo> f1{0, Foo{}};  // Calls move ctor
  cout << "------------------------\n";

  pair<uint32_t, Foo> f2{0, {}};     // Calls copy ctor
  cout << "------------------------\n";

  return 0;
}

В результате

create foo

move foo

delete foo

------------------------

create foo

copy foo

delete foo

------------------------

delete foo

delete foo

1 Ответ

4 голосов
/ 11 апреля 2020

Давайте посмотрим на два конструктора с двумя аргументами pair: [pair.pair]

EXPLICIT constexpr pair(const T1& x, const T2& y);
template<class U1, class U2> EXPLICIT constexpr pair(U1&& x, U2&& y);

Второй конструктор использует идеальную пересылку и U2 не может быть выведено из {}. Поэтому первая версия выбирается при использовании {}. Когда вместо этого используется Foo{}, аргумент имеет тип Foo, поэтому U2 определяется как Foo, что приводит к выбору версии переадресации.

...