Приведенный ниже код компилируется (gcc 4.7.2 или icc 13) и выдает «1 2» вывод. Который означает, что const
квалификатор отброшен, т.е. е., f<int&>
имеет тип параметра int&
,
Почему это происходит? Как я понимаю, согласно §14.3.1.4:
Если шаблон-аргумент для шаблона-параметра
T
называет тип «ссылка на CV1S
»Попытка создать тип« ссылка на CV2T
Создает тип «ссылка на CV12S
«, где CV12 это объединение cv-квалификаторов CV1 а также CV2. Избыточные cv-квалификаторы игнорируются.
const
не должен быть уронен. Вот код:
#include <iostream>
using namespace std;
template <typename T>
void f(const T& t)
{
t++;
}
int main()
{
int a = 1;
cout << a;
f<int&>(a);
cout << ' ' << a << endl;
return 0;
}
GCC 4.7.2 делает не скомпилируйте это, когда флаг -std=c++98
указан. На самом деле, в C ++ 98 (как и в C ++ 03) ссылки на ссылки не разрушаются.
Попытка создания экземпляра f<int&>
, где T = int&
, выдает следующую сигнатуру функции (здесь я намеренно переключаю позицию типа аргумента T
и const
спецификатор, который разрешен, потому что const T&
такой же как T const&
):
void f(int& const& t) // ERROR: reference to reference is illegal
Вышесказанное недопустимо ни в C ++ 98, ни в C ++ 03. Соответственно, это ошибка, которую вы получаете из GCC 4.7.2:
Compilation finished with errors:
source.cpp: In function 'int main()':
source.cpp:15:14: error: no matching function for call to 'f(int&)'
source.cpp:15:14: note: candidate is:
source.cpp:5:6: note: template<class T> void f(const T&)
source.cpp:5:6: note: template argument deduction/substitution failed:
source.cpp: In substitution of 'template<class T> void f(const T&) [with T = int&]':
source.cpp:15:14: required from here
source.cpp:5:6: error: forming reference to reference type 'int&'
Тем не менее, если вы используете -std=c++11
флаг, то компилятор выполняет свертывание ссылок при создании экземпляра шаблона: ссылка lvalue на ссылку lvalue становится ссылкой lvalue:
void f(int& const& t) == void f(int& t)
Здесь const
квалификатор удаляется, потому что это относится к ссылке, а не к указанному объекту. Поскольку ссылки не могут быть переназначены, они const
по природе, поэтому const
считается лишним и удаленным. Увидеть этот вопрос&А на ТАК для объяснения.
Это дает ссылку lvalue на ссылку lvalue, которая преобразуется в простую ссылку lvalue. Следовательно, подпись на правой стороне создается.
Вышесказанное является подходящим кандидатом для решения проблемы f<int&>(a)
и, следовательно, он компилируется без ошибок.
Вот 1770 год, где, кажется, возникла данная цитата:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1770.html
14.3.1 — Аргументы типа шаблона
-4- Если аргумент шаблона для параметра шаблона T называет тип «lvalue-ссылка на cv1 S», «попытка создать ссылку типа (lvalue или rvalue) на cv2 T» создает тип «lvalue-ссылка на cv12 S, «где cv12 — объединение cv-квалификаторов cv1 и cv2. Если аргумент шаблона называет тип «rvalue-ссылка на cv1 S», попытка создать тип «lvalue-ссылка на cv2 T» создает тип «lvalue-ссылка на cv12 S.» Если аргумент шаблона называет тип «rvalue-ссылка на cv1 S», попытка создать тип «rvalue-ссылка на cv2 T» создает тип «rvalue-ссылка на cv12 S.» Избыточные cv-квалификаторы игнорируются.
Вот 2118, где цитата была вычеркнута:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html
14.3.1 — Аргументы типа шаблона
-4- Если аргумент шаблона для параметра шаблона Т называет тип
«ссылка на cv1 S»это ссылка на тип A, попытка создать тип«ссылка на cv2 T»«lvalue-ссылка на cv T» создает тип«ссылка на cv12 S», где cv12 — объединение cv-квалификаторов cv1 и cv2. Избыточные cv-квалификаторы игнорируются«lvalue-ссылка на A», в то время как попытка создать тип «rvalue-ссылка на cv T» создает тип T.
То, что вы цитируете, кажется устаревшей формулировкой.