Ответ 1
", поскольку функция, которая принимает ссылку rvalue, может принимать как ссылки rvalue (неназванные временные), так и ссылки lvalue (называемые неконстантными ссылками)"
Это неправильный оператор. Во время первых итераций справочной спецификации rvalue это было правдой, но она больше не существует и реализована, по крайней мере, в MSVC, чтобы соответствовать этому более позднему изменению. Другими словами, это незаконно:
void f(char&&);
char x;
f(x);
Чтобы вызвать функцию, ожидающую ссылки rvalue с lvalue, вы должны превратить ее в rvalue следующим образом:
f(std::move(x))
Конечно, этот синтаксис достаточно четко показывает, какая разница между функцией, принимающей ссылку на lvalue, и ссылкой на rvalue на самом деле: ссылка на rvalue не должна пережить вызов. Это большое дело.
Теперь вы можете, конечно, создать новую функцию, которая делает именно то, что std:: move делает, а затем вы "можете" использовать ссылки rvalue вроде ссылок на lvalue. Я думал об этом, например, с картой посетителя, которую я имею, когда иногда вы просто не заботитесь о каком-либо результате обращения к посетителю, но в других случаях вы делаете и, следовательно, нуждаетесь в ссылке lvalue в этих случаях. С ссылкой на rvalue я мог получить оба... но это такое нарушение ссылочной семантики rvalue, что я решил, что это плохая идея.
Ваше выражение может быть путаницей, основанной на этом:
template < typename T >
void f(T&&);
char x;
f(x);
Это работает, но не потому, что вы передаете lvalue как ссылку rvalue. Он работает из-за ссылочного распада (также нового в С++ 0x). Когда вы передаете lvalue на такой шаблон, он фактически создается таким образом:
void f<char&>(char&&&);
Ссылочный распад говорит, что &&&
превращается в &
, поэтому фактическое создание экземпляра выглядит следующим образом:
void f<char&>(char&);
Другими словами, вы просто передаете lvalue по ссылке... ничего нового или особого в этом вопросе.
Надеюсь, что это очистит.