The implementation of add_rvalue_reference

60 Views Asked by At

Why does the result become an rvalue reference when deducing from a function returning type directly for a function type, while the implementation in bool_constant yields the correct type?

#include <type_traits>

using namespace std;

template <typename T>
T &&test_rvalue_reference(int);
template <typename T>
T test_rvalue_reference(...);

static_assert(is_same_v<decltype(test_rvalue_reference<void ()>(0)), add_rvalue_reference_t<void ()>>);     // error
static_assert(is_same_v<decltype(test_rvalue_reference<void ()>(0)), void (&)()>);      // OK, lvalue reference


template <typename, typename T>
struct select_second_type {
    using type = T;
};
template <typename T>
typename select_second_type<T &&, true_type>::type try_add_rvalue_reference(int);
template <typename T>
false_type try_add_rvalue_reference(...);

template <typename T, bool = decltype(try_add_rvalue_reference<T>(0))::value>
struct add_right_value_reference {
    using type = T &&;
};
template <typename T>
struct add_right_value_reference<T, false> {
    using type = T;
};

static_assert(is_same_v<typename add_right_value_reference<void ()>::type, add_rvalue_reference_t<void ()>>);       // OK
static_assert(is_same_v<typename add_right_value_reference<void ()>::type, void (&&)()>);       // OK, rvlaue reference
1

There are 1 best solutions below

0
Artyer On BEST ANSWER

There are no function rvalues. An expression which nominally has type void(&&)() (or any "rvalue-reference to function type") is actually still an lvalue, not an xvalue.

So your decltype(test_rvalue_reference<void ()>(0)) has type void() (Remember, an expression can't have a reference type) and is an lvalue, so the decltype yields void(&)().

Compare this with decltype(test_rvalue_reference<int>(0)): This has type int and is an xvalue, so the decltype yields the expected int&&.