Ссылка на значение в C ++ 11 и ссылка на константу - PullRequest
0 голосов
/ 30 августа 2018

Это может быть очевидно, но я думаю, что это что-то трудное для меня. Учитывая это:

void test(std::string&&) { }

std::string x{"test"};
test(std::move(x)); // ok

Этот код вызывает test() со ссылкой на rvalue в качестве параметра, поэтому программа компилируется, как я ожидал.

Теперь посмотрите на это:

void other_test(const std::string&) { }

std::string x{"test"};
other_test(std::move(x)); // ok???

И вот я наклонился. Почему эта версия компилируется? std::move возвращает тип &&; почему тогда я не получаю ошибку во втором методе, где я использую const&?


Я знаю, что

int&& s = 5;
const int& s = 5;

действительно, потому что в обоих случаях я предоставляю что-то, что не имеет lvalue, у него нет адресов. * && и const& эквивалентны? Если нет, есть ли различия?

Ответы [ 5 ]

0 голосов
/ 31 августа 2018

Когда вы вызываете std::move(x), будет возвращена ссылка rvalue на базовые данные test. Вам разрешено передавать rvalue ссылки как const (и только константы!) параметры ссылки, поскольку ссылка rvalue неявно преобразуется в ссылку const. Они возможно, то же самое с точки зрения функции (параметр только для чтения). Если вы удалите const-квалификатор вашего параметра, этот код не скомпилируется:

void other_test(std::string&) { }
std::string x{"test"};
other_test(std::move(x)); //not okay because
//the function can potentially modify the parameter.

См. видео YouTube Бо Цяня о rvalue vs lvalue .

0 голосов
/ 30 августа 2018

Если вы хотите, чтобы функция явно разрешала объекты const-Lvalue, но явно запрещала объекты Rvalue, напишите сигнатуру функции следующим образом:

void test(const std::string&) { }
void test(std::string&&) = delete;//Will now be considered when matching signatures

int main() {
    std::string string = "test";
    test(string);//OK
    //test(std::move(string));//Compile Error!
    //test("Test2");//Compile Error!
}
0 голосов
/ 30 августа 2018
test(std::string&& a) {
  something(a) //--> not moved because it has lvalue

Имена переменных являются lvalues. a - это имя переменной, поэтому a - это выражение lvalue, и поэтому оно не будет перемещено из.

Непонятно, что вы подразумеваете под "имеет". a это выражение. Это имя ссылки, а ссылки ссылаются на объекты. Категории значений относятся к выражениям, а не к объектам.

test(const std::string& a): a является константной ссылкой на lvalue и, как и прежде, у меня есть lvalue и rvalue. И плюс еще, в этом случае, если бы я позвонил

std::move(a)

где a - const и ход работает!

Если под «работами» вы подразумеваете, что он вызывает конструктор или присваивание перемещения, то нет, он не работает, поскольку не было построений или присваиваний перемещения.

0 голосов
/ 30 августа 2018

Проще говоря:

  • && может связываться с неконстантными значениями (значениями и значениями)
  • const && может связываться с r-значениями (постоянными и неконстантными)
  • & может связываться с неконстантными значениями
  • const & может связываться с rvalues ​​(prvalues ​​и xvalues) и lvalues ​​(const и non-const для каждого). А.К.А. ни к чему.
0 голосов
/ 30 августа 2018

std::move на самом деле ничего не выводит из себя. Это просто причудливое название для приведения на T&&. Вызов test как этот test(std::move(x)); только показывает, что T&& неявно преобразуется в const T&. Компилятор видит, что test принимает только const T&, поэтому он преобразует T&&, возвращенный из std::move в const T&, и это все, что нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...