Pytanie Dlaczego dodanie `const` czyni odniesienie uniwersalne rwartością


Czytałem o uniwersalnych odniesieniach w ostatnim ostatnim dziele Scotta na temat c ++ 11 i 14, z tym, że pomimo argumentu przypisanego do lwartości lub parametru referencyjnego typu rvalue istnieje coś pośredniego, nazywane uniwersalnym odniesieniem, które mogłoby wydedukować albo l / rvalue na podstawie cechy typu argumentu, który minął. Mogłem zrozumieć, co czyni parametr uniwersalnym odniesieniem, ale jedyną rzeczą, która nie jest dla mnie jasna, jest to, dlaczego dodawałem const do parametru typu const T&& p zrób p jako wartość:

template<typename T>
void f(T&& param); // param is an universal reference

template<typename T>
void f(const T&& param); // param is an rvalue reference

Czy const Zrób więcej niż to, gdy jest przypisane do parametru referencyjnego.


16
2017-08-07 14:09


pochodzenie




Odpowiedzi:


Oficjalna nazwa nie jest uniwersalnym odniesieniem, ale przekazanie przekierowania. The Standard stwierdza, że ​​tylko odwołania do wartości r cv - niewykwalifikowany parametry szablonu należą do tej kategorii:

14.8.2.1 Wyznaczanie argumentów szablonu z wywołania funkcji [temp.deduct.call]

3 Jeśli P jest typem kwalifikowanym cv, to kwalifikatory cv najwyższego poziomu typu P   są ignorowane dla odliczenia typu. Jeśli P jest typem odniesienia, typ   określony przez P jest używany do odliczenia typu. Odesłanie przesyłania to   wartość rvalue dla parametru szablonu bez cv. Jeśli P jest a   odniesienie do przekazywania i argumentem jest l-wartość, typ "l-wartość   odniesienie do A "stosuje się zamiast A do odliczenia typu. [Przykład:

template <class T> int f(T&& heisenreference);
template <class T> int g(const T&&);
int i;
int n1 = f(i); // calls f<int&>(int&)
int n2 = f(0); // calls f<int>(int&&)
int n3 = g(i); // error: would call g<int>(const int&&), which
               // would bind an rvalue reference to an lvalue

- przykład końcowy]

Pozwalać const T&& zachowywać się jak referencje przekazujące, uniemożliwiłoby przeciążenie funkcji szablonu, która jako parametr przyjmuje tylko wartość odniesienia rvalue.

Aktualizacja: jak @HowardHinnant wspomina w komentarzach, const T&& ma swoje zastosowania (patrz także ten Q & A).


12
2017-08-07 15:27



Aby powrócić do części 24 w Efektywny nowoczesny C ++ który pomieszał OP, Scott opisuje (luźno) uniwersalne odniesienia do referencji rwartości w kontekście dedukcji typu. Pierwsze (nieuwzględnione) zdanie w cytowanym powyżej standardzie 14.8.2.1 ("Jeśli P jest typem kwalifikowanym cv, to kwalifikatory cv najwyższego poziomu typu P są ignorowane dla odliczenia typu") jasno wyjaśnia oświadczenie Scotta, że "Nawet prosta obecność a const kwalifikator wystarczy, aby zdyskwalifikować odniesienie z bycia uniwersalnym " (cytat z książki, poz. 24). - dfri
@dfri Dzięki, nie miałem w pobliżu cyfrowej kopii EMC ++. - TemplateRex
Więcej motywacji co do tego, dlaczego: Czasami musimy powiedzieć: Nie wiąż do rwartości, tylko do wartości l: template <class T> void cref(const T&&) = delete;. - Howard Hinnant
@HowardHinnant zaktualizowany o link do innego pytania i odpowiedzi, w którym wyjaśniłeś, że w głębi, tnx! - TemplateRex
"zezwalanie na zachowanie stałych T && jako odniesień do przekazywania, może prowadzić do wiążących wartości rvalue do l-wartości.", mówiąc ściśle, nie jest to prawdą. Gdyby const T&& może używać jako odniesienia do przekazywania, możemy wywnioskować T tak jak int & w g(i), a następnie zwinąć do const int &, który wiąże stałą wartość odniesienia do lwartości. Problem polega na tym, że nie mielibyśmy możliwości przeciążenia funkcji szablonu, która przyjmuje tylko wartość rvalue jako parametr, jeśli oba T && i const T && mogą używać jako odniesienia do przekazywania. - Carousel