Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm writing a network library and use move semantics heavily to handle ownership for file descriptors. One of my class wishes to receive file descriptor wrappers of other kinds and take ownership, so it's something like

struct OwnershipReceiver {   template <typename T>   void receive_ownership(T&& t)   {      // taking file descriptor of t, and clear t   } }; 

It has to deal multiple unrelated types so receive_ownership has to be a template, and to be safe, I wish it ONLY binds to rvalue references, so that user has to explicitly state std::move when passing an lvalue.

receive_ownership(std::move(some_lvalue));

But the problem is: C++ template deduction allows an lvalue to be passed in without extra effort. And I actually shot myself on the foot once by accidentally passing an lvalue to receive_ownership and use that lvalue(cleared) later.

So here is the question: how to make a template ONLY bind to rvalue reference?

like image 982
Ralph Zhang Avatar asked Oct 23 '11 00:10

Ralph Zhang


People also ask

Can lvalue bind to rvalue reference?

An lvalue reference can bind to an lvalue, but not to an rvalue.

How do you pass rvalue reference to a function?

If you want pass parameter as rvalue reference,use std::move() or just pass rvalue to your function.

Is an rvalue reference an rvalue?

An rvalue reference is formed by placing an && after some type. An rvalue reference behaves just like an lvalue reference except that it can bind to a temporary (an rvalue), whereas you can not bind a (non const) lvalue reference to an rvalue.

What is a const rvalue reference?

You probably haven't seen any practical code that uses const rvalue references ( const T&& ). And that's not really surprising. The main purpose of rvalue references is to allow us to move objects instead of copying them. And moving the state of an object implies modification.


1 Answers

You can restrict T to not be an lvalue reference, and thus prevent lvalues from binding to it:

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

It might also be a good idea to add some sort of restriction to T such that it only accepts file descriptor wrappers.

like image 55
Howard Hinnant Avatar answered Sep 22 '22 19:09

Howard Hinnant