Как можно получить ссылку на rvalue?

Я использовал std::move а также std::forward в C++. Мой вопрос: как эти функции на самом деле реализуются стандартной библиотекой?

Если lvalue - это то, что вы можете получить по адресу, а rvalue не является исключительно lvalue, как вы можете на самом деле реализовать эти ссылки?

Разве эти новые возможности позволяют что-то вроде:

auto x = &(3); 

или что-то типа того? Можете ли вы получить ссылку на значение, которое не просто std::move/forward вернул lvalue?

Надеюсь, эти вопросы имеют смысл. Я не смог найти хорошую информацию в Google, только учебники по идеальной пересылке и т. Д.

3 ответа

Решение

Я не могу вызвать функцию: void foo(string* bar) как это: foo(&string("Hello World!")) или я получаю ошибку:

ошибка: получение временного адреса

Я также не могу вызвать функцию: void foo(string& bar) как это: foo(string("Hello World!")) или я получаю ошибку:

ошибка: неверная инициализация неконстантной ссылки типа 'std::string& {aka std::basic_string&}' из значения типа 'std::string {aka std::basic_string}'

Что C++11 предоставил мне возможность сделать, так это сделать ссылку на rvalue, чтобы я мог вызвать функцию: void foo(string&& bar) как это: foo(string("Hello World!"));

Кроме того, внутренне foo Я могу получить адрес объекта, переданного по ссылке rvalue:

void foo(string&& bar){
    string* temp = &bar;

    cout << *temp << " @:" << temp << endl;
}

Похоже, у ОП действительно хороший контроль над значениями. Но это их объяснение было полезно для меня, а может и для других. В нем подробно рассказывается о том, почему C++03 допускает постоянные ссылки на rvalue по сравнению с C++11 ссылками на rvalue.

Как можно получить ссылку на rvalue?

Концептуально выражение rvalue создает временный объект или иногда обозначает существующий объект. Это может быть связано со ссылкой, как и любой другой объект; но, чтобы избежать путаницы, язык допускает это только для const lvalue ссылки.

Я использовал std::move и std::forward в C++. Моя проблема в том, как это на самом деле реализуется компилятором?

move просто возвращает rvalue ссылку на свой аргумент, эквивалентный

static_cast<typename remove_reference<T>::type&&>(t)

Результатом вызова функции является rvalue (в частности, xvalue), поэтому его можно привязать к ссылке rvalue, где аргумент функции не может. Это позволяет вам явно перейти от lvalue, используя move преобразовать его в значение, не позволяя случайно от него переместиться.

forward аналогично, но перегружен для возврата ссылки rvalue на ссылку rvalue или rvalue и ссылку lvalue на что-либо еще.

Если значение l является чем-то, вы можете получить адрес

Это более или менее правильно. Официальное определение заключается в том, что выражение "обозначает функцию или объект", и это те вещи, которые имеют адреса.

и значение r исключительно не является значением l

На самом деле, нет. Упрощенно говоря, выражение является либо lvalue, либо rvalue, но может быть преобразовано из одного в другое. Значение l может быть неявно преобразовано в значение r; преобразование в другую сторону может быть сделано с помощью приведения, как move делает.

как вы можете реализовать эти ссылки?

Как и любая другая ссылка - как псевдоним или указатель на объект, с которым он связан. Единственное отличие состоит в том, какие виды выражений могут использоваться для обозначения (и, возможно, создания) объекта, который связан с ссылкой.

Разве эти новые возможности позволяют что-то вроде auto x = &(3);

Это пытается получить адрес rvalue напрямую, что недопустимо. Поскольку речь идет о ссылках, а не указателях, допустимо следующее, связывающее ссылку с временным объектом (время жизни которого увеличивается для соответствия ссылке):

auto && rvalue = 3;
auto const & const_lvalue = 3;

пока не разрешено связывать его с неконстантной ссылкой lvalue

auto & lvalue = 3;  // ERROR

В основном, магия компилятора. Стандарт описывает правила, производитель компиляторов просто должен выяснить, как реализовать правила.

На практике ссылки либо оптимизируются, либо реализуются как указатель на уровне процессора.

std::move не очень особенный в этом смысле. Он имеет ссылку lvalue в качестве входных данных и ссылку rvalue в качестве выходных данных. Компилятор просто должен применить правила ввода rvalue к входным данным.

Точно так же цель std::forward<T> это просто сказать компилятору применить другой набор правил к аргументу, правила, которые должны быть определены так, чтобы идеальная пересылка работала. Сама функция ничего не делает.

Другие вопросы по тегам