C ++ 98/03 свертывание ссылок и cv квалификаторы

Приведенный ниже код компилируется (gcc 4.7.2 или icc 13) и выдает «1 2» вывод. Который означает, что const квалификатор отброшен, т.е. е., f<int&> имеет тип параметра int&,

Почему это происходит? Как я понимаю, согласно §14.3.1.4:

Если шаблон-аргумент для шаблона-параметра T называет тип «ссылка на CV1 S»Попытка создать тип« ссылка на CV2 TСоздает тип «ссылка на CV12 S«, где 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;
}

6

Решение

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) и, следовательно, он компилируется без ошибок.

4

Другие решения

Вот 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.

То, что вы цитируете, кажется устаревшей формулировкой.

4

По вопросам рекламы [email protected]