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?
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With