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

1

12

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?

Banbury answered 13/12, 2018 at 9:35 Comment(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.Phraseogram
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.Banbury
Ok there is a suggestion to use is_rvalue_reference<T&&>::value instead and I think I can see why in combination with @songyuanyao's answerBanbury
K
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
}
Kast answered 13/12, 2018 at 9:40 Comment(2)
Could you give some concrete examples to clarify?Banbury
@Banbury Sorry I went wrong direction. Fixed.Kast

© 2022 - 2024 — McMap. All rights reserved.