Почему T && создается как int &?
Может кто-нибудь объяснить, почему это компилируется и почему t
заканчивается типом int&
?
#include <utility>
void f(int& r)
{
++r;
}
template <typename Fun, typename T>
void g(Fun fun, T&& t)
{
fun(std::forward<T>(t));
}
int main()
{
int i = 0;
g(f, i);
}
Я вижу это на GCC 4.5.0 20100604 и GDB 7.2-60.2
Ответы
Ответ 1
Из-за совершенной пересылки, когда аргумент P&&
является lvalue, тогда P
будет выводиться на тип аргумента плюс привязка &
. Таким образом, вы получаете int & &&
с P
int&
. Если аргумент представляет собой rvalue, тогда P
будет выводиться только для типа аргумента, поэтому вы получите аргумент int&&
с P
int
, если вы передадите, например, 0
напрямую.
int& &&
будет сжиматься до int&
(это семантический вид - синтаксически int& &&
является незаконным. Но говоря U &&
, когда U
является параметром шаблона или typedef, ссылающимся на тип int&
, то U&&
по-прежнему является типом int&
- т.е. две ссылки "сворачиваются" на одну ссылку lvalue). Вот почему t
имеет тип int&
.
Ответ 2
Если по какой-то причине вы действительно хотите привязываться к значениям lvalues или rvalues, используйте метапрограммирование:
#include <type_traits>
template <typename T>
typename std::enable_if<std::is_lvalue_reference<T&&>::value, void>::type
fun(T&& x)
{
std::cout << "lvalue argument\n";
}
template <typename T>
typename std::enable_if<std::is_rvalue_reference<T&&>::value, void>::type
fun(T&& x)
{
std::cout << "rvalue argument\n";
}
int main()
{
int i = 42;
fun(i);
fun(42);
}