为什么 std::is_rvalue_reference 没有按照广告宣传的那样去做?

Why does std::is_rvalue_reference not do what it is advertised to do?

例如,如果我有

#include <type_traits>

struct OwnershipReceiver
{
  template <typename T,
            class = typename std::enable_if
            <
                !std::is_lvalue_reference<T>::value
            >::type
           >
  void receive_ownership(T&& t)
  {
     // taking file descriptor of t, and clear t
  }
};

复制自How to make template rvalue reference parameter ONLY bind to rvalue reference?

张贴者使用 !std::is_lvalue_reference 而不是立即更明显的 std::is_rvalue_reference。我已经在我自己的代码中验证了这一点,前者有效而后者无效。

谁能解释为什么显而易见的方法不起作用?

因为对于 forwarding referenceT 永远不会被推导为右值引用。假设将类型为 int 的对象传递给 OwnershipReceiver,如果对象是左值,则 T 将被推导为左值引用,即 int&;如果对象是右值,T 将被推断为非引用,即 int。这就是 std::is_rvalue_reference<T>::value 不起作用的原因,因为它总是 false.

请注意,代码的目的是确保 OwnershipReceiver 的参数类型是右值引用,这并不意味着 T 的类型也是右值引用.

换句话说,这里的重点是区分左值引用和非引用,所以!std::is_reference<T>::value也可以。


顺便说一句:如果你坚持 std::is_rvalue_reference,你可以使用 comment 中的 std::is_rvalue_reference<T&&>::value,或者在参数 t 上使用它,例如

template <typename T>
auto receive_ownership(T&& t) -> typename std::enable_if<std::is_rvalue_reference<decltype(t)>::value>::type      
{
   // taking file descriptor of t, and clear t
}