L-значения сильно предпочитают привязку к ссылкам-значениям, и аналогично ссылки-значения сильно предпочитают привязку к ссылкам-значениям. Изменяемые выражения слабо предпочитают привязку к неконстантной ссылке.
Поэтому, когда ваш компилятор выполняет разрешение перегрузки, он проверяет, есть ли перегрузка, которая принимает ссылку на rvalue, потому что это сильно предпочтительнее. В этом случае, так как эксперимент представляет собой изменяемое значение r, выигрывает эталонная перегрузка rvalue.
На самом деле есть использование для константных ссылок на rvalue, они могут быть использованы, чтобы убедиться, что не не связывается с rvalue. Помните, что rvalue связывается с константной lvalue ссылкой, следовательно, если вы это сделали:
template <typename T> void foo(const T& bar) { /* ... */ }
И вызвал функцию с помощью:
foo(createVector());
Это будет работать нормально. Однако иногда желательно убедиться, что вы можете передавать только значения l в функцию (это относится к std::ref
для одного). Вы можете добиться этого, добавив перегрузку:
template <typename T> void foo(const T&&) = delete;
Помните, что rvalues настоятельно предпочитает привязку к ссылкам rvalue, а модифицируемые выражения предпочитают слабую привязку к неконстантным ссылкам. Поскольку у нас есть const rvalue-reference, это в основном означает, что каждое отдельное rvalue будет связываться с этим, следовательно, если вы попытаетесь передать rvalue в foo()
, ваш компилятор выдаст ошибку. Это единственный способ достичь такой функциональности, и поэтому он иногда полезен.