Какой тип константной ссылки?
Я знаю, что передача константной ссылочной переменной в константный ссылочный параметр функции не приводит к тому, что параметр функции имеет тип "константная ссылка на константную ссылку типа рефери". Имя переменной аргумента const reference просто рассматривается как другой псевдоним для рефери, но прославляется защитой, что указанный псевдоним не может использоваться для изменения рефери.
Идея использования имени ссылочной переменной, как если бы он был псевдонимом переменной referee, применима к переменным, что дает еще один уровень косвенности. Похоже, не имеет смысла применять аналогичные идеи:
- сам ссылочный тип const используется так, как если бы он был псевдонимом типа его рефери,
-
typedef
ссылочного типа const, используемого в качестве псевдонима типа его рефери, - константная ссылочная переменная, переданная (или выведенная)
template
Параметр получает свой тип, интерпретируемый как тип его рефери, когда параметр шаблонаtypename T
и его функциональный параметрT const&
,
Но вот что, похоже, происходит в следующем:
#include <typeinfo>
#include <iostream>
template <typename T>
T const& min(T const& a, T const& b) {
std::cout << typeid(a).name() << std::endl;
std::cout << typeid(b).name() << std::endl;
return a < b ? a : b;
}
int main() {
int x = 6, y = 7;
int const& rx = x;
std::cout << typeid(rx).name() << std::endl; // "int"
int z = ::min(rx, y); //output shows both "a" and "b" are of type "int"
std::cout << z << std::endl; // “6”
typedef int const& icr;
std::cout << typeid(icr).name() << std::endl; // "int"
std::cout << typeid(int const&).name() << std::endl; // "int"
}
Почему шаблон функции работает даже для аргументов, которые уже
int const&
? (В примере кода это работало даже для вызова, который имелint const&
переменная в качестве первого параметра иint
переменная как вторая.) Разве это не должно быть недействительным, потому что C++ не допускает "ссылку на ссылку"?Не должен
typeid
"sname()
изint const&
бытьint const&
, вместоint
?Если нет, то это не значит
int const&
псевдонимint
; что не имеет никакого смысла, потому что оба являются разными типами (не именами переменных)?Возвращаясь к именам переменных, учитывая:
int num = 8; int const& ref = num; std::cout << typeid(ref).name() << std::endl;
почему выход
int
, и неint const&
?
2 ответа
Аргументы функции - это выражения, а не объекты. Даже если вы предоставляете один объект в качестве аргумента функции, он все равно является выражением. Процесс вывода аргументов шаблона не будет работать с объявленным типом этого объекта. Это не заботится о его точно объявленном типе. Что его волнует, так это тип этого выражения.
Выражения в C++ никогда не интерпретируются как имеющие ссылочный тип. Каждое выражение, которое физически имеет ссылочный тип, всегда интерпретируется как lvalue (или xvalue) не ссылочного типа. "Ссылочная" часть немедленно и необратимо отбрасывается и забывается.
Вот как это сформулировано в стандарте (5/5)
5 Если выражение изначально имеет тип "ссылка на T" (8.3.2, 8.5.3), тип корректируется до T перед любым дальнейшим анализом. Выражение обозначает объект или функцию, обозначенную ссылкой, и выражение является lvalue или xvalue, в зависимости от выражения.
Например, в вашем коде rx
объявлен как int const &
, Тем не менее, каждый раз, когда вы используете rx
как выражение, результат этого выражения всегда сразу корректируется из int const &
в int const
и рассматривается как ценность int const
тип. В контексте "выражения результата" язык полностью игнорирует тот факт, что rx
была ссылка.
Часто говорят, что ссылка может рассматриваться как просто другое имя для существующего объекта. Это именно тот принцип, который работает здесь. В контексте "выражения результата" нет никакой разницы между rx
а также x
(кроме const-квалификации).
Возвращаясь к вашему коду, в этом звонке
int z = ::min(rx, y);
аргументы функции интерпретируются как l-значения int const
а также int
тип соответственно. (Т.е. первый аргумент на самом деле не рассматривается как имеющий int const &
типа, вопреки вашим ожиданиям). Эти типы используются для вывода аргументов шаблона. Как следствие, T
выводится как int
, Ни в одной точке этого процесса попытка создать "ссылку на ссылку" не имеет шансов иметь место.
typeid
работает так, как вы наблюдаете по той же причине. typeid
не дает вам заявленный тип объекта. Аргумент typeid
в твоем случае это выражение. typeid
в этой форме дает тип результата выражения, поэтому typeid
не может "видеть" ссылки. const
часть отбрасывается, потому что это только как typeid
работает: cv-qulifiers верхнего уровня всегда отбрасываются typeid
,
Поскольку ссылки свернуты в контексте вывода типа, как и
const
s. Посмотрите, как разваливается ссылка, на нее уже много ответов.Нет, потому что ссылки прозрачны, вы не можете смотреть на них; когда вы называете переменную, которая является ссылкой, язык всегда думает, что вы имеете в виду рефери. Когда ты
typeid
ссылки илиconst
это игнорирует это.Избегайте полужирных неважных слов, таких как переменные, это затрудняет чтение вашего вопроса:)