2012-10-06 9 views
11

Niedawno zostały następnie dyskusję o przydziale do wyrażeń C++, jak pokazano w poniższym przykładzie:Czy należy używać kwalifikatorów referencyjnych Lvalue dla operatorów przypisania?

string s1, s2, s3; 
(s1 + s2) = s3; 

z C++ 11 możliwe jest ograniczenie operatorowi przypisanie do lwartości odniesienia (po lewej stronie). Podczas deklarowania operatorów przypisania w następujący sposób, Clang kompilatora odrzuca kod z komunikatem o błędzie z powodu niezgodności typów.

auto operator=(const string& rhs) & -> string&; 
auto operator=(string&& rhs) & -> string&; 

Nigdzie tego nie widziałem. Czy istnieje dobry powód, aby nie używać kwalifikatorów referencyjnych Lvalue dla operatorów przypisania (poza brakiem wsparcia w większości kompilatorów)?

+5

Jednym z powodów jest to, że większość kompilatorów nie obsługuje jeszcze składni. Innym jest to, że nie rozwiązuje * poważnego problemu *. Jak często to się dzieje przez pomyłkę? –

+1

Myślę, że to się zdarza. 'if (somefunc() = value)' Oczywiście większość kompilatorów wysyła ostrzeżenie, ale nie we wszystkich przypadkach. –

Odpowiedz

4

Nie, niezupełnie. Używanie kwalifikatorów do wartości lub rvalue do konstruowania poprawnego interfejsu dla obiektów o wartości lwartość lub rwartości jest takie samo jak przy użyciu const i należy podchodzić w ten sam sposób - każda funkcja powinna być brana pod uwagę jako ograniczenie. Przypisanie do wartości runtue nie ma większego sensu, więc powinno być zabronione.

Powodem nie widzieliście najczęściej jest to biedny kompilator wsparcie-bibl rvalue dla *this jest trochę jak thread_local większość realizatorów kompilator wydaje się umieścić go w pobliżu dolnej części „Elementy do wdrożenia od C++ 11” stos.

+0

Moim zdaniem najlepsza odpowiedź. Chociaż byłem bardziej zainteresowany operatorem przypisania, ponieważ jest on specjalną funkcją członka. Używanie kwalifikatorów referencji może mieć pewien wpływ na regułę 5, dziedziczenie, bycie zmienną składową agregatu lub użycie ze standardowymi kontenerami i biblioteką standardową. Jednak powinienem był prosić o te informacje. – nosid

8

Interesujące! Nie zdawałem sobie nawet z tego sprawy i zabrałem mnie, aby go znaleźć (było to częścią propozycji "Extending move semantics to *this"). Zapis jest zdefiniowany w 8.3.5 [dcl.decl] pkt 4, na wypadek gdyby ktokolwiek chciał spojrzeć.

W każdym razie: Teraz, wiedząc o tej funkcji, wydaje się, że najbardziej użyteczne jest używanie jej do przeciążania i być może zachowywać się inaczej, jeśli obiekt, na który wywoływana jest funkcja, jest lwartością lub rwartością. Używanie go w celu ograniczenia tego, co można zrobić, np. Z wynikiem przypisania, wydaje się niepotrzebne, szczególnie jeśli obiekt faktycznie jest l-wartością. Na przykład, możesz chcieć składni powrót rvalue przypisywanie do rvalue:

struct T { 
    auto operator=(T&) & -> T&; 
    auto operator=(T&&) & -> T&; 
    auto operator=(T&) && -> T; 
    auto operator=(T&&) && -> T; 
}; 

Zamiarem tutaj byłoby, aby umożliwić przejście od wyniku cesji (czy to warto, chociaż nie jestem na pewno: dlaczego nie pominąć zadania?). Nie sądzę, żebym użył tej funkcji przede wszystkim do ograniczenia zastosowań.

Osobiście lubię możliwość, że czasami zdobędę lwartość z wartości runtu, a operator przydziału jest często sposobem na zrobienie tego. Na przykład, jeśli chcesz przejść lwartością do funkcji, ale wiesz, że nie chcesz korzystać z niego nic, można użyć operatora przypisania zdobyć lwartością:

#include <vector> 
void f(std::vector<int>&); 
int main() 
{ 
    f(std::vector<int>() = std::vector<int>(10)); 
} 

To może być nadużycie operatora przydziału, aby uzyskać lwartość z wartości r, ale jest mało prawdopodobne, aby stało się przez przypadek. W związku z tym nie zejdę mi z drogi i uniemożliwię to poprzez ograniczenie operatora przypisania do zastosowania tylko do l-wartości. Oczywiście, zwrot rinktu z zadania do rwartości również zapobiegłby temu. Które z tych dwóch zastosowań jest bardziej przydatne, jeśli w ogóle, może być brane pod uwagę.

BTW, clang wydaje się wspierać składnię cytowaną od wersji 2.9.

+5

Wolałbym mieć jasne 'template T & as_lvalue (T && v) {return v; } 'funkcja niż wkręcanie się w umysły moich kolegów programistów, którzy zastanawiają się, co do cholery próbujesz osiągnąć przy pomocy zadania (które, dla ruchu - nieświadomego, wydaje się zawierać niepotrzebną kopię" wektora "). – Xeo

3

Jednym z powodów, dla których nie jestem bardzo entuzjastą Twojej sugestii, jest to, że I'm trying to shy away from declaring special members altogether. Większość moich operatorów przypisania jest w ten sposób domyślnie zadeklarowanych, a zatem nie ma żadnych kwalifikatorów.

Oczywiście dla tych czasów, kiedy piszę szablon klasy lub klasy, np. zarządzać własnością (patrz zawarcie w powyższym linku), mógłbym zadeklarować tych operatorów tylko dla wartości l. Nie ma to jednak większego znaczenia, ponieważ nie ma wpływu na klientów.

+0

Zgadzam się z tobą. Jeśli to możliwe, unikam zadeklarowania któregokolwiek z 5. Jednak operator przypisania przypisania generowany przez kompilator nie jest ograniczony do odniesień do lwartości. Najprawdopodobniej będzie kompatybilny wstecz. – nosid

Powiązane problemy