C ++ 0x: ссылка на значение по сравнению с неконстантным значением - PullRequest
12 голосов
/ 23 декабря 2010

При программировании на C ++ 03 мы не можем передать неназванный временный T() в функцию void foo(T&);.Обычное решение состоит в том, чтобы дать временному имя и затем передать его следующим образом:

T v;
foo(v);

Теперь вместе с C ++ 0x - и теперь со ссылками на rvalue функция, определенная как void foo(T&&), позволитмне пройти временный.Это подводит меня к моему вопросу: поскольку функция, которая принимает ссылку на rvalue, может принимать как ссылки на rvalue (неназванные временные ссылки), так и ссылки на lvalue (именованные неконстантные ссылки), есть ли какая-либо причина использовать ссылки lvalue в параметрах функции?Разве мы не должны всегда использовать rvalue в качестве параметров функции?

Конечно, функция, которая принимает ссылку на lvalue, не позволит вызывающей стороне передать временную функцию, но я не уверен, что этоПолезное ограничение.

Ответы [ 2 ]

19 голосов
/ 23 декабря 2010

", поскольку функция, которая принимает ссылку на rvalue, может принимать как ссылки на rvalue (неназванные временные ссылки), так и ссылки на lvalue (именованные неконстантные ссылки)"

Это неверное утверждение.На первых итерациях эталонной спецификации rvalue это было правдой, но она больше не применяется и реализуется, по крайней мере, в MSVC, чтобы соответствовать этому более позднему изменению.Другими словами, это недопустимо:

void f(char&&);

char x;
f(x);

Чтобы вызвать функцию, ожидающую ссылки rvalue с lvalue, вы должны превратить ее в значение r следующим образом:

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.Это работает из-за затухания ссылок (также нового в C ++ 0x).Когда вы передаете lvalue в такой шаблон, он на самом деле создается, например, так:

void f<char&>(char&&&);

Распад эталона говорит о том, что &&& превращается в &, поэтому фактическое создание экземпляра выглядит так:1022 *

Другими словами, вы просто передаете lvalue по ссылке ... ничего нового или особенного в этом нет.

Надеюсь, что все прояснится.

0 голосов
/ 23 декабря 2010

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

...