2015-06-25 17 views
19

Rozważ tę prostą parę szablonów funkcji.Przeciążenie i częściowe zamawianie szablonów

template <typename T> 
void foo(T&) { std::cout << __PRETTY_FUNCTION__ << '\n'; } 

template <typename C> 
void foo(const C&) { std::cout << __PRETTY_FUNCTION__ << '\n'; } 

Jeżeli nazywamy foo z const argumentu:

int i = 4; 
foo(i); 

Przeciążenie T& jest korzystny na podstawie [over.ics.rank] /3.2.6, ponieważ jest wyprowadzona odniesieniu int& mniej cv - zakwalifikowany niż wyliczony odnośnik const int&.

Jednakże, jeśli nazywamy foo z const argumentu:

const int ci = 42; 
foo(ci); 

Przeciążenie const C& jest korzystny, ponieważ jest "bardziej wyspecjalizowane" na podstawie [over.match.best] /1.7. Ale jakie są zasady, aby to ustalić? Zrozumiałem, że syntetyzujesz typ dla C (zadzwoń, M) i spróbuj wykonać dedukcję na foo(M) - ale to się uda (z T == M). To tylko wartość, która spowodowałaby, że dedukcja się nie udała - ale skąd kompilator wie, że musi wybrać rwartość w etapie syntezy?

Odpowiedz

20

Nota prawna: Rodzaje, które rozważamy, są zawsze typami parametrów. Rodzaje/kategorie wartości/etc. Rzeczywiste argumenty są brane pod uwagę wyłącznie przy rozładowaniu, nigdy w częściowym porządkowaniu.

częściowe uporządkowanie uwzględnia zarówno przeciążeń w dwóch „zakrętów”, w którym jeden szablon jest zawsze taki szablon parametr, a drugi szablon jest szablonem argumentem. [temp.deduct.partial]/2:

Dla każdego z zastosowanych szablonów istnieje oryginalny typ funkcji i typ przekształconej funkcji. [..] Proces dedukcji wykorzystuje transformowany typ jako szablon argumentu i oryginalny typ innego szablonu jako szablonu parametru. Ten proces jest wykonywany dwa razy dla każdego typu porównywania częściowego: : raz wykorzystując transformowany szablon-1 jako szablon argumentu jako szablon parametrów i ponownie używając szablonu przekształconego jako szablonu argumentu i szablon-1 jako szablon parametrów .

Powinieneś znać sposób, w jaki generowane są transformowane "szablony". Jest to określone w §14.5.6.2/3.

celu wytworzenia stransformowanej szablon dla każdego typu, dla typu lub szablon szablonu parametru (w tym parametry szablonu pakuje (14.5.3) ich) syntezy unikalny rodzaj, wartość lub klasy szablon odpowiednio i zastąp go dla każdego wystąpienia tego parametru w typie funkcji szablonu.

Więc nasze szablony (przekształcone) argumentów są

void foo(Unique1&); 

void foo(Unique2 const&); 

[temp.deduct.partial]/3 &/4:

Typy używane do określenia kolejność zależą od kontekst w , którego częściowe zamówienie zostało wykonane:

  • W kontekście wywołania funkcji używane typy to te typy parametrów funkcji dla , których wywołanie funkcji ma argumenty. [..]

Każdy typ mianowany powyżej z szablonu parametru i odpowiedniego typu z matrycy argumentu stosowane są jako typy P i A.

Tak więc mamy dwa zakręty, a obie mamy typ P i typ A:

Włącz 1:
        P1:     T const&
        A1 :     Unique1&

Turn 2:
        P2:     T&
        A2:     Unique2 const&

Ale zanim zacznie się zabawa, niektóre transformacje są wykonywane na tych typów, a także - I skrócona [temp.deduct.partial]/5 &/7:

  • Jeśli wartościami są P lub A, są one zastępowane typem, do którego się odnoszą.
  • Wszystkie kwalifikatory cv najwyższego poziomu są usuwane.

Należy zauważyć, że usunięte kwalifikatory cv są "zapamiętywane" na później. [Temp.deduct.partial]/6:

Jeśli zarówno P i A były typu odniesienia (przed zastąpiony typu, o którym mowa wyżej) określenia, który z dwóch typów (jeśli występuje) jest bardziej cv-kwalifikowany od drugiego; w przeciwnym razie typy te są uznawane za równoważne z cv dla celów częściowego zamawiania. Wynik tego oznaczenia zostanie użyty poniżej.

Tak więc jesteśmy w lewo z

Kolejką 1:
        P1:     T
        A1:     Unique1

Turn 2:
        P2:     T
        A2:     Unique2

Teraz wykonujemy odliczenia - która jasno powiedzie w obu turach ustawiając T=Unique[1/2]. Od [temp.deduct.partial]/8:

Jeżeli odliczenie udaje dla danego rodzaju, typu z szablonu argumentu jest uważany być co najmniej tak wyspecjalizowanym jako typ z matrycy parametrów.

To daje nam zarówno, że Unique1& jest przynajmniej jako wyspecjalizowane T const&, a Unique2 const& jest przynajmniej jako wyspecjalizowane T&.


Jednak to gdzie [temp.deduct.partial]/(9,2) etapy:

Jeśli dla danego typu, odliczenie powiedzie się w obu kierunkach (czyli ów są identyczne po powyższych transformacjach) i oba P i A zostały typy odniesienia (przed wymianą z rodzaju, o którym mowa wyżej) :

  • [..]; w przeciwnym razie,

  • jeśli typ z szablonu argumentu jest bardziej cv wykwalifikowany niż typu z matrycy parametru (jak opisano powyżej), typ parametr nie jest uważane za co najmniej wyspecjalizowane jako argument rodzaj.

zapamiętany CV kwalifikacyjnych wchodzą w grę. A2 jest „więcej cv zakwalifikowanych (jak opisano powyżej)” niż P2 stąd P2 nie są uważane za co najmniej jako wyspecjalizowane A2.

Wreszcie, [temp.deduct.częściowy]/10:

szablon funkcji F jest co najmniej jako wyspecjalizowane matrycy funkcji G Jeżeli dla każdej pary typach wykorzystywane do określenia uporządkowania, rodzaju z F jest co najmniej tak wyspecjalizowane, jak rodzaj od G.
F jest bardziej wyspecjalizowany niż G jeśli F jest co najmniej tak wyspecjalizowane jak G i G nie jest przynajmniej jako wyspecjalizowane F.

zakłada, że ​​skoro typ T& jest przynajmniej nie jako wyspecjalizowaną jak Unique2 const& a my już ustalone, że T const& jest co najmniej tak wyspecjalizowane jak Unique1& The T const& -overload jest bardziej wyspecjalizowane niż T& -overload.


Powyższa zasada w pkt 9 jest obecnie przedmiotem CWG #2088 stworzył cztery miesiące temu przez R. Smith:

Późne tiebreakers dla lwartość-vs-rvalue odniesień i CV-kwalifikacji w 14,8 .2.4 [temp.deduct.partial] pkt 9 są stosowane

Jeśli dla danego typu, odliczenie powiedzie się w obu kierunkach (tj rodzaje są identyczne po powyższych transformacjach) i oba P i A były typu odniesienia (przed zastąpione typu określonego powyżej )

Jednak ta opiera się na założeniu, fałszywego. [..] Musimy zdecydować, czy zasada brzmi: "dedukcja odnosi sukces w obu kierunkach", czy "typy są identyczne". Ten ostatni wydaje się bardziej rozsądny.

Nie zmieni to wyniku ustalonego, ponieważ typy, które otrzymaliśmy, są rzeczywiście identyczne.