2013-05-11 22 views
6

Wiem, że w C++ 03, niestanowiące odniesienia nie mogą być powiązane z wartościami r.Czy poprawne jest wiązanie nie-stałych wartości l-odniesień do wartości r w C++ 11? (Zmodyfikowane)

jest nieważny, aw języku C++ 11 możemy to zrobić: T&& t = getT();, ale co z powyższym kodem, czy to powinno działać w C++ 11?

Testowałem kody poniżej 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 to klasa zwyczaj, nie rozumiem, dlaczego dwie pierwsze linia compiles.The tymczasowy odwołuje z jest zniszczona pod koniec wewnętrzna zakres główny. Czy standard mówi coś na ten temat?

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

Właśnie widziałem podobne pytanie: One VS2010 bug ? Allowing binding non-const reference to rvalue WITHOUT EVEN a warning?

+4

To ciekawe, jak * kilka * programistów Objective-C lub Java zadawać pytania na temat języka zorientowanego ezoteryki jak „Czy to ważne, aby związać rvalues do niestałych wartości l-odniesień ...? " Albo muszą się zajmować takimi rzeczami jak "tymczasowe odniesienia ... zniszczone na końcu wewnętrznego zakresu". Po prostu mów:;) – paulsm4

+0

Czy mógłbyś opublikować, jak zdefiniowałeś Foo? – Gisway

+0

wiążące zasady nie uległy zmianie W przypadku Lvalue odniesienia AFAIK –

Odpowiedz

5

czy to powinno działać w języku C++ 11?

Nie, nie powinien.

Foo jest niestandardowej klasy, ja nie rozumiem, dlaczego dwie pierwsze linia kompiluje

kompiluje tylko z MSVC. MSVC ma (prawdopodobnie użyteczne) rozszerzenie kompilatora, które pozwala na związanie lwartości typów zdefiniowanych przez użytkownika z wartościami r, ale sam Standard zabrania tego. Zobacz na przykład this live example, gdzie GCC 4.7.2 odmawia skompilowania kodu.

Czy standard mówi coś na ten temat?

Rzeczywiście tak. Za punkt 8.5.3/5 C++ 11 Standard:

odniesienie wpisać „cv1 T1” jest inicjowany przez wyrażenie typu „cv2 T2” w następujący sposób:

- Jeśli odwołanie jest lwartością odniesienia i wyrażenie inicjator

- jest lwartością (ale nie jest to bitowe pole) i „cv1 T1” odniesienia jest zgodny z „cv2 T2” lub

- ma typ klasy (tj. T2 jest typem klasy), gdzie T1 nie jest związany z odniesieniem do T2 i może być niejawnie przekonwertowany na lwartość typu "cv3 T3", gdzie "cv1 T1" jest kompatybilny z „cv3 T3” [...]

następnie odniesienia jest związany z lwartości ekspresji inicjatora w pierwszym przypadku i lwartością wyniku konwersji w drugim przypadku (albo w każdym przypadku, aby odpowiedni obiekt podrzędny klasy podstawowej obiektu o numerze ). [...]

[...]

- przeciwnym razie referencyjna wynosi lwartością odniesienie do nieulotnej typu const (tj CV1 będzie const) lub odniesienia określane być referencją rvalue. [Przykład:

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 

końcem przykład]

0

No nie można powiązać tymczasowy do const odniesienia lwartości.

T f(); 

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

To jest funkcja zabezpieczająca. Mutacja tymczasowa o l-wartości, która i tak ma umrzeć, jest najprawdopodobniej błędem logicznym, więc nie jest dozwolona przez język.

Należy pamiętać, że ze względu na RVO niż w praktyce:

T&& t3 = f(); 

i

T t3 = f(); 

są equivilent.