Универсальная ссылка на C и вывод типа параметра LRef

#c #c 11 #reference #forwarding-reference

#c #c 11 #ссылка #пересылка-ссылка

Вопрос:

Предположим, у нас есть некоторый код

 template <typename T>
void Foo(Tamp;amp; param);

int x = 5;
// deduced Foo<intamp;>(intamp;).
// Argument type A = int. T = intamp;.
Foo(x);     

intamp; rx = x;
// deduced Foo<intamp;>(intamp; amp;amp;) -> Foo<intamp;>(intamp;).
// But... argument type A = intamp;, an lvalue reference to int.
// Is T = intamp; or under the hood it is T = intamp; amp;?
Foo(rx);
  

Согласно https://en.cppreference.com/w/cpp/language/template_argument_deduction

4) Если P является ссылкой rvalue на параметр шаблона, не отвечающий требованиям cv (так называемая ссылка пересылки), и соответствующий аргумент вызова функции является значением lvalue, ссылка типа lvalue на A используется вместо A для вычитания

Что я хочу знать: применяются ли правила свертывания ссылок к выведенному типу T (не к P, типу параметра)?

Итак, действительно ли у нас есть для ‘Foo (rx)’ T = int amp; amp; , который свернулся до T = int amp;?

Ответ №1:

Обратите внимание, что практически для всех технических целей тип выражения никогда не считается ссылочным типом. [expr.type]/1:

Если выражение изначально имеет тип «ссылка на T » ([dcl.ref], [dcl.init.ref]), тип корректируется до T перед любым дальнейшим анализом.

Единственное заметное исключение — это когда decltype() применяется к непарентифицированному имени или выражению доступа к члену класса. Хотя синтаксис рассматривает имя как выражение, семантический результат включает объявленный тип имени, вместо типа выражения и категории значения.

Итак, в вашем примере x является значением типа int , а rx является значением типа int . После их объявления и инициализации язык вообще не делает различий между ними, за исключением, опять же, случаев, когда вы используете decltype(x) или decltype(rx) .

Это означает, что вывод типа шаблона для Foo(rx) работает точно так же, как для Foo(x) : тип A является int , не intamp; , а аргументом является значение lvalue. Согласно приведенному вами правилу, T выводится как intamp; , и при замене T=intamp; в тип функции правило свертывания ссылок говорит, что Tamp;amp; является intamp; .