Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

For example if I have

#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
  }
};

copied from How to make template rvalue reference parameter ONLY bind to rvalue reference?

the poster uses !std::is_lvalue_reference instead of the immediately more obvious std::is_rvalue_reference. I've verified this in my own code where the former works and the later doesn't.

Can anybody explain why the obvious doesn't work?

like image 960
bradgonesurfing Avatar asked Dec 13 '18 09:12

bradgonesurfing


1 Answers

Because for forwarding reference, T will never be deduced as an rvalue reference. Suppose passing an object of type int to OwnershipReceiver, if the object is an lvalue, T will be deduced as an lvalue-reference, i.e. int&; if the object is an rvalue, T will be deduced as an non-reference, i.e. int. That's why std::is_rvalue_reference<T>::value won't work because it's always false.

Note that the purpose of the code is to make sure the parameter type of OwnershipReceiver is an rvalue-reference, it doesn't mean the type of T is an rvalue-reference too.

In other words, the point here it to distinguish lvalue-reference and non-reference, so !std::is_reference<T>::value works too.


BTW: If you stick to std::is_rvalue_reference, you can use std::is_rvalue_reference<T&&>::value as you found in the comment, or use it on the parameter t, e.g.

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
}
like image 72
songyuanyao Avatar answered Nov 07 '22 17:11

songyuanyao