Использование семантики перемещения с помощью std:: pair или std:: tuple

Предположим, вы хотите использовать семантику перемещения, но один из ваших подвижных классов должен быть частью std::pair. Целью было бы создать функцию, которая возвращает std::pair, которая может рассматриваться как rvalue, и перенаправляется вперед.

Но я не вижу, как это можно сделать, если не сделано внутреннее изменение в std::pair, чтобы он знал о семантике перемещения.

Рассмотрим следующий код:

struct Foo
{
 Foo() { }

 Foo(Foo&& f) { }

 private:

 Foo(const Foo& f) { } // do not allow copying
};

int main() 
{
 Foo f;
 std::pair<Foo, int> res = std::make_pair(f, 10); // fails due to private copy constructor
}

Проблема заключается в том, что std::make_pair, а также сам конструктор std::pair принимает два объекта и пытается сделать их внутренними копиями. Это заставляет его попробовать и вызвать конструктор копирования. Но в моем примере я хочу иметь возможность переместить новую пару в res и гарантировать, что никакие копии не будут сделаны. Я думаю, что это было бы невозможно, если только std::pair сам не определил следующий конструктор:

pair(T1&& t1, T2&& t2) : first(std::move(t1)), second(std::move(t2))

Но это не так, по крайней мере, не на компиляторе, который я использую (gcc 4.3.2). Возможно, мой компилятор просто устарел, а более новые версии на самом деле будут иметь этот конструктор с поддержкой перемещения. Но мое понимание семантики движения в настоящий момент несколько шепотливо, поэтому я не уверен, что я просто пропущу что-то здесь. Итак, я пытаюсь сделать это, не переосмысливая std::pair? Или мой компилятор просто устарел?

Ответы

Ответ 1

Это не конструктор std::pair, который будет вызываться. Будет вызываться конструктор перемещения std::pair, и конструктор перемещения должен делать то, что вы ожидаете (N3126 20.3.5.2/6):

template<class U, class V> pair(pair<U, V>&& p);

Эффекты: конструктор сначала инициализируется std::move(p.first), а второй - std::move(p.second).

Однако ваш пример должен завершиться неудачно, потому что в std::make_pair(f, 10);, f является значением l и должно быть явно move d, иначе оно будет скопировано. Должно работать следующее:

std::pair<Foo, int> res = std::make_pair(std::move(f), 10);

Ответ 2

GCC 4.3.2 не должен иметь полной реализации. пара (и кортеж) должны иметь конструкторы перемещения:

template<class U, class V> pair(U&& x, V&& y);
Эффекты: конструктор сначала инициализирует std:: forward (x), а второй - std:: forward (y).
template<class U, class V> pair(pair<U, V>&& p);
Эффекты: конструктор сначала инициализирует std:: move (p.first), а второй - std:: move (p.second).

(From [pairs.pair] в n3126)