При применении const
к T
, который выводится как ссылка Lvalue (например, при передаче Lvalue функции, принимающей универсальную ссылку), модификатор игнорируется. Предположим, мы передаем обычное L-значение int
, const T
, которое должно быть преобразовано в const int&
, преобразуется просто в int&
.
Вот пример:
#include <iostream>
template<typename T>
const T foo(T&& a)
{
// const T b{ 1 }; This would result in compile-error, cause b is just int&
const T b{ a };
return b;
}
int main()
{
int x = 5;
foo(x);
}
Вот что я получил в C++ Insights:
#include <iostream>
template<typename T>
const T foo(T && a)
{
const T b = {a} /* NRVO variable */;
return b;
}
/* First instantiated from: insights.cpp:13 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
int & foo<int &>(int & a)
{
int & b = {a}; // As you see I'm getting an int& here and in return type also
return b;
}
#endif
int main()
{
int x = 5;
foo(x);
return 0;
}
Вы можете решить эту проблему, применив std::remove_reference
к T
, а затем добавив const
и ссылку, например:
#include <iostream>
#include <type_traits>
template<typename T>
const std::remove_reference_t<T>& foo(T&& a)
{
const std::remove_reference_t<T>& b{ a };
const std::remove_reference_t<T>& c{ 5 }; // Can use Rvalues now
return b;
}
int main()
{
int x = 5;
foo(x);
}
Мне просто интересно, есть ли у такого поведения какое-то объяснение? Где еще может возникнуть такое поведение? Если я что-то упустил, буду рад вашим комментариям.
Это помогает мыслить в терминах восточных констант. Квалификаторы типа const
ассоциируются слева, за исключением случаев, когда слева ничего нет, но const T
и T const
на самом деле означают одно и то же. const
относится ко всему T
, если смотреть на него с правой (восточной) стороны.
Когда T
равно int&
, тогда const T
становится int& const
, что довольно бессмысленно, поскольку ссылка в любом случае неизменна.
Если бы это были указатели, было бы понятнее. Если T
равно int*
, то const T
и T const
становятся int* const
, что является неизменяемым указателем, но объект, на который он указывает, не является const
и его можно изменить:
using T = int*;
int x = 10;
const T b = &x;
*b = 20; // x is now 20
// b = &x; // error, the pointer is const so you can't assign to it