C ++ копировать, перемещать конструкторы - PullRequest
0 голосов
/ 14 декабря 2018

У меня есть код здесь:

#include <string>
#include <iostream>
#include <initializer_list>

template <typename T>
class Test
{
public:
  Test(std::initializer_list<T> l)
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }

  Test(const Test<T>& copy)
  {
    std::cout << __PRETTY_FUNCTION__ << std::endl;
  }
  Test(Test&&) = delete;
  Test() = delete;
};

void f(const Test<Test<std::string>>& x)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
}

void f(const Test<std::string>& x)
{
  std::cout << __PRETTY_FUNCTION__ << std::endl;
  f(Test<Test<std::string>>{x});
}

int main()
{
  Test<std::string> t1 {"lol"};
  f(t1);
  return 0;
}

Я пытаюсь скомпилировать это с GCC 7.3.0 на моем linux mint 19 с помощью команды:

g ++ -std = c ++11 -O0 test.cpp -o test -Wall -pedantic

Компиляция завершается с ошибкой, что этот вызов:

f(Test<Test<std::string>>{x});

Требуется конструктор перемещения, но он удален.Я всегда думал, что конструкторы перемещения и копирования эквивалентны с точки зрения компиляции, потому что rvalue может быть привязано к константной ссылке, но перегрузка с явно определенной ссылкой на rvalue просто имеет приоритет в разрешении перегрузки.Это первый раз, когда я вижу, что компилятору на самом деле требуется конструктор перемещения, и он не просто использует копию.Зачем?Я что-то упустил?

Ответы [ 2 ]

0 голосов
/ 14 декабря 2018

Вы явно объявили конструктор перемещения и пометили его как delete, он будет выбран по разрешению перегрузки, а затем вызовет ошибку.

Если предусмотрены конструкторы копирования и перемещения иникакие другие конструкторы не являются жизнеспособными, разрешение перегрузки выбирает конструктор перемещения, если аргумент является rvalue того же типа (значение x, например, результат std :: move or a prvalue such as a nameless temporary (until C++17)), и выбирает конструктор копирования, если аргумент является lvalue(именованный объект или функция / оператор возвращают ссылку на lvalue).

Обратите внимание, что *1001* удаленный неявно -объявленный конструктор перемещения игнорируется разрешением перегрузки, но явно -объявленный не будет.

Удаленный неявно объявленный конструктор перемещения игнорируется разрешением перегрузки (иначе это предотвратит инициализацию копирования из rvalue).(начиная с C ++ 14)

0 голосов
/ 14 декабря 2018

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

Вы правы в этом предположении.Если у вас есть набор перегрузки, который принимает const& и &&, то версия && предпочтительнее, чем const&, если у вас есть значение.Проблема в том, что ваша && версия помечена как удаленная.Это означает, что вы явно заявляете, что не хотите, чтобы его можно было конструировать из временного кода, и код не сможет скомпилироваться.

В этом случае, если вы не хотите, чтобы класс был подвижным, вы можете просто получитьизбавиться от

Test(Test&&) = delete;

Так как наличие вашего определяемого пользователем конструктора копирования удалит компиляторы автоматически сгенерированного конструктора перемещения.

...