Функция двойная для std::move?

Предположим, у меня есть класс только с одним конструктором:

class T {
 public:
  T(BigClass&& big) : big(std::move(big)) {}
  ...

  SomeBigClass
};

В большинстве случаев конструктор вызывается для временных объектов, но в одном месте мне нужно сделать явную копию BigClass, потому что он не является временным и будет использоваться несколько раз в цикле:

void foo(const BigClass& big) {
  while (...) {
    T t(std::make_a_copy(big));
    ...
  }
}

Есть ли какая-нибудь функция, «двойная» для std::move в С++ 11 или С++ 14, которая заменит make_a_copy выше?

Изменить: некоторые пояснения.


person Łukasz Lew    schedule 05.07.2013    source источник
comment
Если вам может понадобиться сделать копию, то не должны ли вы также предоставить конструктор T(BigClass const & big), а затем вместо этого вызвать его?   -  person cdhowie    schedule 06.07.2013
comment
Почему вам нужно сделать копию temporary вместо перемещения? Это кажется каким-то неразумным.   -  person Xeo    schedule 06.07.2013
comment
Кто-то, вероятно, должен отклонить мое редактирование.   -  person Pixelchemist    schedule 06.07.2013
comment
Если вы хотите написать как можно меньше функций, двумя основными являются конструктор копирования и swap. Конструктор перемещения, присваивание копирования и присваивание перемещения можно записать в терминах конструктора копирования и свопинга. Без конструктора копирования... без ярлыков.   -  person Mooing Duck    schedule 06.07.2013
comment
Этот вопрос совершенно не связан с тем, что написано в заголовке. Двойник std::move потребуется в ситуации, когда у вас есть выражение ссылки rvalue и вам нужна модифицируемая ссылка lvalue (которая не будет привязана, если вы напишете ее таким образом, и создайте временную из rvalue тоже не будет работать, потому что он может инициализировать только ссылки const lvalue). Здесь это не так, у вас прямо противоположная ситуация; его можно было бы скомпилировать с помощью std::move, но это не делает того, что вы хотите. Решение состоит в том, чтобы сначала скопировать значение big, которое не связано с вашим class T.   -  person Marc van Leeuwen    schedule 21.07.2014
comment
В этом примере foo(const BigClass&) (const ref!) конструктор перемещения уже будет не вызываться, так как вы не можете выйти из константного объекта.   -  person Martin Ba    schedule 19.11.2014
comment
У вопроса есть дубликат, который предоставляет дополнительную информацию.   -  person Martin Ba    schedule 19.11.2014


Ответы (3)


Почему нельзя просто скопировать объект BigClass?

void foo(const BigClass& big) {
  while (...) {
    T t{ BigClass(big) };
    ...
  }
}

Это создает временный BigClass, который затем перемещается в T

person Jonathan Wakely    schedule 06.07.2013
comment
Это не похоже на то, что ему даже нужна явная копия. - person Xeo; 07.07.2013
comment
@Xeo: Да, для этого нужна явная копия; в вопросе явно говорится, что уникальный конструктор T принимает BigClass&&, в частности, нет конструктора T::T(const BigClass&), использование которого создавало бы и связывало временное для вас. - person Marc van Leeuwen; 21.07.2014

Не сложно написать:

template <typename T>
T make_temp(const T& x) { return x; }

Может быть стандартная функция, которая делает это случайно при вызове с одним аргументом, но нет ни одной, разработанной для этого необычного шаблона.

person aschepler    schedule 07.07.2013

Если вы можете манипулировать T, вы можете создать шаблон конструктора.

#include <iostream>
using namespace std;
class B
{
  int x;
public:
  B (int i) : x(i) { }
  B (B && b) : x(b.x) { cout << "B moved (" << x << ")" << endl; }
  B (B const  & b) : x(b.x)  { cout << "B copied (" << x << ")" << endl; }
};


class A
{
  B b;
public:
  template<typename TB>
  A (TB && init_b) : b(std::forward<TB &&>(init_b)) { }
};

B foo (void) { B x(3); return x; }


int main (void)
{
  A a1(foo());
  B b1(4);
  A a2(b1);
  return 0;
}

Отпечатки

Б перемещено (3)
Б скопировано (4)

Насколько я понимаю свертывание ссылок, вы должны выйти с конструктором A(B&), пересылающим конструктор копирования B, и A(B&&), пересылающим конструктор перемещения B.

person Pixelchemist    schedule 05.07.2013
comment
Ваш тест глубоко ошибочен. Вы копируете A во второй строке, что, конечно же, копирует элемент b. Кроме того, std::forward<B> приведет к перемещению, только std::forward<B&> приведет к lvalue. - person Xeo; 06.07.2013
comment
Хорошо, до редактирования это было неправильно, но решение шаблона, использующее свертывание ссылок, работает для указанного случая (насколько я могу судить по проверке с std::is_rvalue_reference и std::is_lvalue_reference). Так что, если в этом ответе все еще что-то не так, дайте мне подсказку вместо того, чтобы проголосовать против него без каких-либо комментариев. - person Pixelchemist; 09.07.2013