2012-04-14 17 views
8

Czy ten typ zwracania ma znaczenie w języku C++ 11?semantyka zwrotnego typu odniesienia wartości r?

template <typename R> 
R&& grabStuff(); 

T instance = grabStuff<T>(); 

Mam nadzieję, że grabStuff powinny rzucać się błąd kompilacji, jeśli R nie posiada konstruktora posunięcie, ponieważ byłoby to wydaje się odrzucać typ zwracany do korzystania konstruktor kopiujący

Odpowiedz

5

Jak zawsze, zwracając referencje, musisz zwrócić referencję do czegoś, co wciąż żyje po powrocie funkcji. Jak to zrobisz, zależy od ciebie. Przykład:

T global_thing; 

T && get() { return std::move(global_thing); } 

struct Foo { Foo(T &&); /* ... */ }; 

int main() 
{ 
    global_thing.reset(); 
    Foo a(get()); 
    global_thing.reset(); 
    Foo b(get()); 
} 

Bardziej typowym przykładem dla powracających odwołanie rvalue jest sama std::move, choć, która zwraca odwołanie do rzeczy mijamy do to (a więc jest to odpowiedzialność rozmówcy, aby zapewnić prawidłową wejście) .

+0

Obiekt nie musi być obiektem globalnym. Przykładem może być również obiekt lokalny zarządzający zasobami (może: D). – Nawaz

+0

@Kerrek, więc mówisz, że ta funkcja powinna być wywoływana tylko w tymczasowych? czy wynik 'get()' w twoim przykładzie nie może być przypisany do normalnego odniesienia 'Foo &'? – lurscher

+0

@Nawaz: Tak, tak jak powiedziałem, to zależy od ciebie ... Chciałem tylko podać przykład, który nie jest '' std :: move'. –

1

To może mieć znaczenie w zależności od tego, co chcesz z tym zrobić i jak zaimplementowałeś tę funkcję.

W rzeczywistości std::move typu zwrotny jest T&& (odniesienie RValue), co ma znaczenie, jak to określa sam cel istnienia std::move w C++ 11 Biblioteka:

+0

'std :: move' to ** jedyna ** znacząca instancja typu zwracającego wartość rVue. To nigdy nie miałoby znaczenia w kodzie użytkownika. – ildjarn

+0

@ildjarn: Nie mogę twierdzić, że * "To ** nigdy ** nie miałoby znaczenia w kodzie użytkownika" *. Po prostu stwierdzam, że rvalue-reference jako typ zwracany może być znaczący. – Nawaz

+0

Twierdzę, że tak. ; -] W kodzie _użytkownika_ (chyba że ten kod użytkownika powtarza 'std :: move' z jakiegoś dziwnego powodu), typ zwracany referencji rvalue nie może zrobić nic znaczącego semantycznie. – ildjarn

1

Jeśli typ powrotu funkcji jest referencją rvalue, wynikiem wywołania funkcji jest xvalue; jeśli typem zwracanym jest nie-odwołanie, wynikiem wywołania funkcji jest prvalue.

Zarówno wartość x jak i prvalue są wartościami r, istnieją pewne drobne różnice pomiędzy nimi, bardziej przypominają różnice między odniesieniem a brakiem odniesienia. Na przykład wartość x może mieć niekompletny typ, podczas gdy prvalue zwykle ma typ pełny lub typu void. Kiedy typeid zostanie zastosowane do xvalue, której typ jest polimorficznym typem klasy, wynik odnosi się do typu dynamicznego; i dla prvalue, wynik odnosi się do typu statycznego.

Dla twojego oświadczenia deklaracji T instance = grabStuff<T>();, jeśli T jest typem klasy, myślę, że nie ma różnicy między wartością x a wartością w tym kontekście.

Inicjator jest rwartością, więc kompilator preferuje konstruktor ruchu. Ale jeśli nie zostanie zadeklarowany żaden konstruktor ruchu i zadeklarowany zostanie konstruktor kopiowania z parametrem odwołania, to zostanie wybrany ten konstruktor kopiowania i nie wystąpi błąd. Nie wiem, dlaczego chcesz, żeby to był błąd. Jeśli jest to błąd, każdy stary kod będzie niepoprawny, jeśli zainicjować kopię jakiegoś obiektu z wartości r.

Powiązane problemy