Почему эта функция возвращает ссылку на lvalue с заданными аргументами rvalue?

Следующее определениеmin функция

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

есть проблема: кажется, что это совершенно законно, чтобы написать

min(10, 20) = 0;

Это было проверено с Clang 3.5 и g ++ 4.9.

Решение простое, просто используйтеstd::forward восстановить "значение" аргументов, то есть изменить тело иdecltype сказать

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

Тем не менее, я затрудняюсь объяснитьЗачем первое определение не генерирует ошибку.

Учитывая мое понимание переадресации и универсальных ссылок, обаt а такжеu вывести их типы аргументов какint&& когда переданы целочисленные литералы. Тем не менее, в телеminАргументы имеют имена, поэтому они являются значениями. Теперьв игру вступают действительно сложные правила для условного оператора, но ясчитать соответствующая строка:

Оба E2 [и] E3 являются glvalues ​​одного типа. В этом случае результат имеет тот же тип и категорию значений.

и, следовательно, тип возвращаемого значенияoperator?: должно бытьint&& а разве не так? Однако (насколько я могу судить) и Clang, и g ++ имеютmin(int&&, int&&) возвращая ссылку lvalueint&, что позволяет мне назначить результат.

Ясно, что в моем понимании есть пробел, но я точно не знаю, что мне не хватает. Кто-нибудь может объяснить мне точно, что здесь происходит?

РЕДАКТИРОВАТЬ:

Как правильно указывает Найл, проблема здесь не в условном операторе (который возвращает lvalue типаint&& как и ожидалось), но сdecltype, Правила дляdecltype сказать

если категория значения выражения lvalue, тогда decltype указывает T &

поэтому возвращаемое значение функции становитсяint&& &, который по правилам свертывания ссылок C ++ 11 превращается в простойint& (вопреки моему ожиданиюint&&).

Но если мы используемstd::forwardпереворачиваем второй и третий аргументыoperator?: (обратно) в rvalues ​​- в частности, xvalues. Поскольку xvalues ​​по-прежнему являются glvalues ​​(вы не отставали от спины?), Применяется то же правило условного оператора, и мы получаем результат с тем же типом и категорией значений:int&& который является xvalue.

Теперь, когда функция возвращается, она вызывает другойdecltype правило:

если значение категории выражения равно xvalue, тогда decltype указывает T &&

На этот раз ссылка рушится дает намint&& && = int&& и, что более важно, функция возвращает значение x. Это делает незаконным присваивать возвращаемое значение, как нам хотелось бы.

Ответы на вопрос(1)

Ваш ответ на вопрос