2012-03-17 43 views
14

To pytanie pochodzi z emisji przedstawionej przez this answer.Rozgałęzienie operatorów przypisania wartościami zamiast odniesień

Zwykle określamy skopiować operatorów przypisania do typu T jak T& operator=(const T&) i przejść dla operatorów przypisania typu T jak T& operator=(T&&).

Co jednak dzieje się, gdy używamy parametru wartości zamiast odniesienia?

class T 
{ 
public: 
    T& operator=(T t); 
}; 

Powinno to spowodować skopiowanie T i przeniesienie przypisania. Jednak chcę wiedzieć, jakie są konsekwencje językowe dla T?

szczególności:

  1. Czy ta liczba w postaci kopii operatora przypisania do T według specyfikacji?
  2. Czy jest to liczone jako operator przydziału przeniesienia dla T, zgodnie ze specyfikacją?
  3. Czy T ma wygenerowanego przez kompilator operator przypisania kopiowania?
  4. Czy T ma wygenerowanego przez kompilator operator przypisania ruchu?
  5. W jaki sposób wpływa to na klasy takie jak std::is_move_assignable?
+0

Powiązane dyskusja: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value – mavam

+0

Dostaję błędy kompilatora zarówno w Visual Studio jak i g ++, jeśli mam coś zarówno T & operator = (T t) i T & operator = (T && t), ponieważ jest niejednoznaczny – user929404

+0

@ user929404: I powinieneś. Chodzi o to, że zastępujesz * obie * zadanie kopiowania i przenoszenia przy użyciu tylko wartości. –

Odpowiedz

14

Większość z nich została opisana w § 12.8. Paragraf 17 określa, co liczy się jako operatorów przypisania kopia użytkownika oświadczył:

Użytkownik zadeklarowana kopia przypisanie operatora X::operator= jest non-static non-szablon funkcji członka klasy X z dokładnie jeden parametr typu X, X&, const X&, volatile X& lub const volatile X&.

Paragraf 19 określa, co liczy się jako move operatorów przypisania użytkownika oświadczył:

Użytkownik zadeklarowana ruch przypisanie operatora X::operator= jest non-static non-szablon funkcji członka klasy X z dokładnie jednym parametr typ X&&, const X&&, volatile X&& lub const volatile X&&.

Oznacza to, że jest to operator przydziału kopiowania, ale nie operator przeniesienia.

Paragraf 18 mówi, gdy kompilator generuje operatory przypisania kopiowania:

Jeżeli definicja klasy nie jawnie zadeklarować kopiowania przypisanie operatora, jeden jest zadeklarowany w sposób dorozumiany. Jeśli definicja klasy deklaruje konstruktor ruchu lub operator przypisania ruchu, domyślnie zadeklarowany operator przypisania kopiowania jest zdefiniowany jako usunięty; w przeciwnym razie wartość jest zdefiniowana jako domyślna (8.4).Ten drugi przypadek jest przestarzały, jeśli klasa ma deklarowany przez użytkownika konstruktor kopii lub zadeklarowany przez użytkownika destruktor z rodziny .

Paragraf 20 mówi nam, gdy kompilator generuje przenieść operatorów przypisania:

Jeżeli definicja klasy X nie jawnie zadeklarować ruch operator przypisania, jeden będzie niejawnie zadeklarowana jako domyślnie jeśli i tylko wtedy, gdy
[...]
- X nie posiada operator przypisania kopia użytkownika oświadczył
[...]

Ponieważ klasa ma zadeklarowany przez użytkownika operator przypisania kopiowania, żaden z plików niejawnych nie zostanie wygenerowany przez kompilator.

std::is_copy_assignable i std::is_move_assignable opisano w tabeli 49 jako posiadający tę samą wartość jak odpowiednio is_assignable<T&,T const&>::value i is_assignable<T&,T&&>::value. Tabela ta mówi nam, że is_assignable<T,U>::value jest true gdy:

Wyrażenie declval<T>() = declval<U>() jest dobrze uformowane podczas leczenia jako unevaluated argumentu (klauzula 5). Kontrola dostępu jest wykonywana jako , jeśli w kontekście niezwiązanym z T i U. Bierze się pod uwagę wyłącznie bezpośredni kontekst wyrażenia przypisania.

Ponieważ zarówno declval<T&>() = declval<T const&>() i declval<T&>() = declval<T&&>() są dobrze uformowane dla tej klasy, to nadal liczy się jako kopię cesji i przenieść przypisane.

Jak już wspomniałem w komentarzach, to, co jest ciekawe, to fakt, że w obecności konstruktora ruchu, ten operator= poprawnie wykona ruchy, ale technicznie nie będzie liczony jako operator przypisania ruchu. Jest jeszcze dziwniej, jeśli klasa nie ma konstruktora kopiowania: będzie miała operatora przypisania kopii, który nie wykonuje kopii, a jedynie ruchy.

Powiązane problemy