Валидно ли е да се обвържат неконстантни lvalue-препратки към rvalues ​​в C++ 11? (модифицирано)

Знам, че в c++03 неконстантна препратка не може да бъде обвързана с rvalues.

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 задават въпроси относно езиково-ориентираната езотерика като Валидно ли е да се обвържат rvalues ​​с неконстантни lvalue-references...? Или трябва да се занимават с неща като временни препратки... унищожени в края на вътрешния обхват. Просто казвам' ;)   -  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)


трябва ли това да работи в c++11?

Не, не трябва.

Foo е персонализиран клас, не разбирам защо се компилират първите два реда

Компилира се само с MSVC. MSVC има (вероятно полезно) разширение за компилатор, което позволява обвързване на lvalues ​​от потребителски дефинирани типове към rvalues, но самият стандарт забранява това. Вижте например този пример на живо, където GCC 4.7.2 отказва да компилира вашия код.

Стандартът казва ли нещо по въпроса?

Наистина е така. Според параграф 8.5.3/5 от стандарта C++11:

Препратка към тип „cv1 T1“ се инициализира от израз от тип „cv2 T2“, както следва:

— Ако препратката е препратка към lvalue и изразът на инициализатора

— е lvalue (но не е битово поле), а „cv1 T1“ е референтно съвместимо с „cv2 T2“, или

— има тип клас (т.е. T2 е тип клас), където T1 не е свързано с препратка към T2 и може да бъде имплицитно преобразувано в lvalue от тип „cv3 T3“, където „cv1 T1“ е съвместимо по референция с „cv3 T3 ” [...],

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

[ ...]

В противен случай препратката трябва да бъде препратка lvalue към енергонезависим тип const (т.е. 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