Por que essa função retorna uma referência lvalue, dados os argumentos rvalue?

A seguinte definição demin função

template <typename T, typename U>
constexpr auto
min(T&& t, U&& u) -> decltype(t < u ? t : u)
{
    return t < u ? t : u;
}

tem um problema: parece perfeitamente legal escrever

min(10, 20) = 0;

Isso foi testado com o Clang 3.5 e g ++ 4.9.

A solução é simples, basta usarstd::forward para restaurar o "valor-valor" dos argumentos, ou seja, modificar o corpo e odecltype dizer

t < u ? std::forward<T>(t) : std::forward<U>(u)

No entanto, não tenho como explicarporque a primeira definição não gera um erro.

Dado meu entendimento de encaminhamento e referências universais, ambost eu deduzir seus tipos de argumento comoint&& quando passados literais inteiros. No entanto, dentro do corpo demin, os argumentos têm nomes e, portanto, são lvalues. Agora oregras realmente complicadas para o operador condicional entram em jogo, mas eupensar a linha pertinente é:

Ambos E2 [e] E3 são glvalues do mesmo tipo. Nesse caso, o resultado tem o mesmo tipo e categoria de valor.

e, portanto, o tipo de retorno deoperator?: deveria estarint&& também, não deveria? No entanto, (até onde eu sei), tanto o Clang quanto o g ++ têmmin(int&&, int&&) retornando uma referência lvalueint&, permitindo-me atribuir ao resultado.

Claramente, há uma lacuna no meu entendimento, mas não tenho certeza exatamente do que estou perdendo. Alguém pode me explicar exatamente o que está acontecendo aqui?

EDITAR:

Como Niall corretamente aponta, o problema aqui não é com o operador condicional (que está retornando um lvalue do tipoint&& conforme o esperado), mas com odecltype. As regras paradecltype dizer

se a categoria de valor da expressão for lvalue, o tipo de declínio especificará T &

então o valor de retorno da função se tornaint&& &, que pelas regras de recolhimento de referência do C ++ 11 se transforma em simplesint& (ao contrário do que eu esperavaint&&)

Mas se usarmosstd::forward, vimos o segundo e o terceiro argumentos deoperator?: (voltar) em rvalues - especificamente, xvalues. Como xvalues ainda são glvalues (você está acompanhando?), A mesma regra de operador condicional se aplica, e obtemos um resultado da mesma categoria de tipo e valor: ou seja, umint&& que é um valor x.

Agora, quando a função retorna, ela dispara uma função diferente.decltype regra:

se a categoria de valor da expressão for xvalue, o tipo de declínio especificará T&&

Desta vez, o colapso de referência nos dáint&& && = int&& e, mais importante, a função retorna um valor x. Isso torna ilegal atribuir ao valor de retorno, como gostaríamos.

questionAnswers(1)

yourAnswerToTheQuestion