Почему T && создается как int &? - PullRequest
11 голосов
/ 01 декабря 2010

Может кто-нибудь объяснить, почему это компилируется и почему 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

Ответы [ 2 ]

17 голосов
/ 01 декабря 2010

Из-за идеальной пересылки, когда аргумент P&& является lvalue, тогда P будет выведен на тип аргумента плюс присоединенный &.Таким образом, вы получаете int & && с P, равным int&.Если аргумент является r-значением, то P будет выводиться только для типа аргумента, поэтому вы получите получите аргумент int&& с P, равным int, если вы передадите, например 0 напрямую.

int& && свернется до int& (это семантическое представление - синтаксически int& && недопустимо. Но высказывание U &&, когда U является параметром шаблона или typedef, ссылающимся на тип int&, тогда U&& по-прежнему является типом int& - т.е. две ссылки «сворачиваются» в одну ссылку lvalue).Вот почему t имеет тип int&.

3 голосов
/ 02 декабря 2010

Если по какой-то причине вы действительно хотите привязать конкретно к 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);
}
...