Calling test(Foo{}) decltype(f) indicates that f was declared as the reference type of rvalue, Foo&& , but the type with which it was declared does not tell you what its category of values ββis (i.e. rvalue or lvalue).
There is an lvalue inside the body of the function f (because it has a name), so decltype(f()) does not match result_of_t<F&&()>
Consider:
Foo&& f = Foo{}; f();
Here, f also declared as the reference type rvalue, Foo&& , but this does not mean that f() calls the && -qualified member function. f is an lvalue, so it causes & -qualified overloading. To call && -qualified overload, you need to use std::move(f)() to make it rvalue.
In your test(F&&) function, where you have a generic reference, you need to use std::forward to restore the category of values ββof the input argument. To get the same type as result_of_t<decltype(f)()> , you need to forward f to restore its original category of values, for example.
using T1 = decltype(std::forward<F>(f)());
Now this type will have the same type as result_of_t<decltype(f)()>
source share