Допустимо ли связывать неконстантные lvalue-ссылки с rvalue в С++ 11? (изменено)

Я знаю, что в С++ 03 неконстантная ссылка не может быть привязана к rvalue.

T& t = getT(); недействителен, и в c++11 мы можем сделать так: T&& t = getT(); но как насчет приведенного выше кода, должен ли он работать в c++11?

Я протестировал приведенные ниже коды с помощью vs11:

 Foo getFoo() {
  return Foo();
}

void fz(Foo& f) {
}

int getInt() {
  return int();
}

void iz(int& i) {
}

int main() {
  {
    Foo& z = getFoo(); //ok
    fz(getFoo()); //ok

    int& z2 = getInt(); //error: initial value of reference to non-const must be an lvalue
    iz(getInt()); //same as above
  }
}

Foo - это пользовательский класс, я не понимаю, почему компилируются первые две строки. Временный объект, на который ссылается z, уничтожается в конце внутренней области действия main. Стандарт что-то говорит об этом?

class Foo {
public:
  Foo() {
    std::cout << "constructed\n";
  }
  ~Foo() {
    std::cout << "destructed\n";
  }
};

Я только что видел похожий вопрос: Одна ошибка VS2010? Разрешить привязку неконстантной ссылки к rvalue ДАЖЕ БЕЗ предупреждения?


person Frahm    schedule 11.05.2013    source источник
comment
Интересно, что немногие программисты на Objective-C или Java задают вопросы о языково-ориентированной эзотерике, например, допустимо ли связывать rvalue с неконстантными lvalue-ссылками...? Или должны заниматься такими вещами, как временные ссылки... уничтожаются в конце внутренней области. Просто говорю' ;)   -  person paulsm4    schedule 11.05.2013
comment
Не могли бы вы опубликовать, как вы определили Foo.   -  person Gisway    schedule 11.05.2013
comment
правила привязки не изменились относительно ссылок Lvalue AFAIK   -  person Koushik Shetty    schedule 11.05.2013
comment
@paulsm4: Извините, у меня не было времени прочитать ваш комментарий, я был слишком занят, ожидая, пока ваш сборщик мусора закончит работу.   -  person Andrew Tomazos    schedule 11.05.2013
comment
@ paulsm4 Вы знаете, что в Objective-C не всегда был автоматический подсчет ссылок. До того, как это было введено, было много беспорядка.   -  person JAB    schedule 15.05.2014


Ответы (2)


должно ли это работать в С++ 11?

Нет, не должно.

Foo - это пользовательский класс, я не понимаю, почему компилируются первые две строки

Компилируется только с MSVC. MSVC имеет (возможно, полезное) расширение компилятора, которое позволяет привязывать lvalue пользовательских типов к rvalue, но сам Стандарт запрещает это. См., например, этот живой пример, где GCC 4.7.2 отказывается компилировать ваш код.

Стандарт что-то говорит об этом?

Действительно так. Согласно параграфу 8.5.3/5 стандарта С++ 11:

Ссылка на тип «cv1 T1» инициализируется выражением типа «cv2 T2» следующим образом:

— Если ссылка является ссылкой lvalue и выражением инициализатора

— является lvalue (но не битовым полем), а «cv1 T1» совместимо по ссылке с «cv2 T2», или

— имеет тип класса (т. е. T2 является типом класса), где T1 не связан со ссылкой на T2 и может быть неявно преобразован в lvalue типа «cv3 T3», где «cv1 T1» совместимо по ссылке с «cv3 T3». [...],

затем ссылка привязывается к выражению инициализатора lvalue в первом случае и к результату преобразования lvalue во втором случае (или, в любом случае, к соответствующему подобъекту базового класса объекта). [...]

[ ...]

В противном случае ссылка должна быть ссылкой lvalue на неизменяемый константный тип (т. е. cv1 должна быть const) или ссылка должна быть ссылкой rvalue. [ Пример:

double& rd2 = 2.0; // error: not an lvalue and reference not const
int i = 2;
double& rd3 = i; // error: type mismatch and reference not const

—конец примера ]

person Andy Prowl    schedule 11.05.2013

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

T f();

T& t1 = f(); // won't compile
const T& t2 = f(); // OK
T&& t3 = f(); // OK

Это функция безопасности. Изменение временного значения lvalue, которое все равно вот-вот умрет, скорее всего, является логической ошибкой, поэтому язык не позволяет это делать.

Обратите внимание, что из-за RVO, чем на практике:

T&& t3 = f();

и

T t3 = f();

эквивалентны.

person Andrew Tomazos    schedule 11.05.2013