#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;
.