11

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?

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
bradgonesurfing
  • 30,949
  • 17
  • 114
  • 217
  • 3
    Did you read the comments on the accepted answer for the question you've linked? Seems to answer your question well enough to me. And if not, it may be useful to include in your question at least one specific example you expect to work that doesn't. – John Ilacqua Dec 13 '18 at 09:40
  • 1
    Did you read the comments? The last comment asks why and there is no answer. It is worth an extra question to clarify the reasoning. – bradgonesurfing Dec 13 '18 at 09:43
  • 1
    Ok there is a suggestion to use is_rvalue_reference::value instead and I think I can see why in combination with @songyuanyao's answer – bradgonesurfing Dec 13 '18 at 09:51

1 Answers1

11

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
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405