2016-02-10 4 views
19

Что здесь происходит? Почему это ошибка?Передача int && в f (int &&)

void f(int &&); 

int && i = 5; 

f(i); 

Разве это не противоречит интуиции?

Я бы ожидал, что i будет ссылкой на rvalue и поэтому сможет передать его f(). Но я получаю сообщение об ошибке;

не известно преобразование из int в int &&

Так что я не думаю, i не является ссылкой Rvalue после объявления?

+1

Что вы надеетесь, произойдет? Что ты пытаешься сделать? Как вы думаете, '&&' означает в этом контексте? – Galik

+0

@Galik, я добавил еще несколько комментариев к моему вопросу. –

+0

Используйте 'std :: move()' для получения ссылки rvalue. –

ответ

19

Здесь существует основное различие между является и связывает. Например:

void f(int &&); 

объявляет функцию приема параметра, который может быть инициализирован только с RValue ссылкой на (типа, конвертируемых в) int.

int && i = 5; 

объявляет именующее выражение, которое может быть инициализирован только с RValue ссылкой на (типа, конвертируемых в) int. Таким образом, в простых терминах,

f(i); 

пытается передать Lvalue ссылку на int в функцию принимающую только RValue ссылки на int. Поэтому он не компилируется.

Чтобы сообщить компилятору, чтобы бросить именующее выражение к RValue, тем самым используя перемещение Конструкторы, где это применимо (хотя и не в случае int), вы можете использовать std::move().

f(std::move(i)); 
+0

В этом случае я бы добавил информацию о 'std :: move'. – Zereges

+0

@ Zereges Хорошая идея. Добавлен. –

+4

Это ** почти ** отличный ответ, но немного неточный. _ "объявляет значение lvalue, которому может быть присвоена только ссылка rvalue на int." _ Нет, он не может быть «назначен» ничем, конечно, не ссылкой на rvalue (поскольку назначение ссылки действительно присваивает веществу, к которой она привязана, но это инициализация не присвоение). Он объявляет lvalue, 'i', типа rvalue-reference, который может быть только инициализирован ** с rvalue (а не rvalue-reference, rvalue). –

16

У него есть название?
Подходит ли он?

Если ответ на оба вопроса - «да», это значение L.

В этом фрагменте: i имеет имя, i имеет адрес (вы можете написать &i), поэтому это значение l.

f(&&) получает значение r-value в качестве параметра, поэтому вам нужно повернуть значение l в значение r-value, которое может быть выполнено с помощью std::move.

f(std::move(i)); 
+0

Примечание. : есть также некоторые lvalues, которые не имеют имен. Кроме того, «Является ли он адресуемым» является круговым определением. Под «адресуемым», я полагаю, вы имеете в виду, «может ли унарный« & »применяться к нему?»; однако определение унарного '&' включает в себя то, что оно может быть применено только к lvalues! –

+0

Ну, счетчики также имеют имена .... – cpplearner

27

Я понимаю, почему вы в замешательстве. Следует помнить, что всякий раз, когда у вас есть имя переменной, у вас есть l-value.

Так что, когда вы говорите:

int i = 0; // lvalue (has a name i) 

А также

int&& i = 0; // lvalue (has a name i) 

Так в чем разница?

int&& может связывать только к г-значение так:

int n = 0; 
int i = n; // legal 

НО

int n = 0; 
int&& i = n; // BAD!! n is not an r-value 

Однако

int&& i = 5; // GOOD!! 5 is an r-value 

Так при переходе i к f() в этом примере вы пропускании л-значение, а не г-значение:

void f(int &&); 

int&& i = 5; // i is an l-value 

f(i); // won't accept l-value 

Ситуация на самом деле немного сложнее, чем я представил здесь. Если вас интересует более полное объяснение, то эта ссылка достаточно полная: http://en.cppreference.com/w/cpp/language/value_category

+2

Отличное объяснение. – erip

+0

Я думаю, что это отличный ответ. Единственное, что я хотел бы предложить, возможно, сделать это более понятным в этом первом предложении, потому что часто «это» можно рассматривать как переменную (хотя это не так), но тогда «это» является prvalue. Можете ли вы придумать какой-либо хороший способ решить эту проблему, или если это действительно актуально? –

+1

@YamMarcovic Я знаю, что ситуация может быть немного сложнее, но я думаю, что для целей обучения лучше представить то, что просто и актуально для примера, который пытается понять ОП. Что я сделаю, так это добавить ссылку для получения дополнительной информации. – Galik

Смежные вопросы