В таком случае, когда вас интересует, почему компилятор выбрал одну перегрузку вместо другой, часто проще (более или менее) напрямую спросить компилятор, как / почему он принял решение, просто разрешив это выбрать другую функцию и посмотреть, какое сообщение об ошибке оно выдает (или может ли оно вообще не выдавать сообщение об ошибке). В этом случае мы можем удалить функцию, взяв ссылку на константное значение, чтобы получить код, подобный этому:
#include <iostream>
using namespace std;
class test { };
// void fun( const test& a)
// {
// cout << "lvalue reference"<<endl;
// }
void fun( test&& a)
{
cout << "rvalue reference"<<endl;
}
const test ff() { } // <<---return value is const now
int main()
{
fun(ff());
}
Теперь, если мы попытаемся скомпилировать, компилятор прямо скажет нам, почему оставшаяся функция не была выбрана:
trash9.cpp:16:3: error: no matching function for call to 'fun'
fun(ff());
^~~
trash9.cpp:8:6: note: candidate function not viable: 1st argument ('const test') would lose const qualifier
void fun( test&& a)
^
Это не так авторитетно, как прямая цитата из стандарта, но компиляторы достаточно хороши в таких вещах, что сообщения об ошибках могут быть довольно информативными.