How about std::rref()?

286 views
Skip to first unread message

eulo...@live.com

unread,
Feb 9, 2014, 6:22:38 AM2/9/14
to std-pr...@isocpp.org
Today I make my first asio program. So I'm very happy.
However, suddenly I found that maybe C++ RAII still have difficulties.

#define ASIO_STANDALONE
#define _WIN32_WINDOWS 0x400
#include<asio.hpp>
#include<exception>
#include<cstdio>
#include<future>
#include<functional>

asio::io_service sev;
asio::ip::tcp::acceptor acc(sev,asio::ip::tcp::endpoint(asio::ip::tcp::v4(),1000));

std::string info(65536,'0');


void async_write(asio::ip::tcp::socket soc)   //I want to move an object to this function to let this function manage its resources.
{
  asio::error_code ign_err;
  asio::write(soc,asio::buffer(info),ign_err);
}

int main()
{
 try
 {
  for(;;)
  {
   asio::ip::tcp::socket socket(sev);
   acc.accept(socket);
   std::async(async_write,std::move(socket));//It can't be compiled.
  }
 }
 catch(std::exception &ex)
 {
  fputs(ex.what(),stderr);
 }
 return 0;
}


std::async(async_write,std::move(socket));//It can't be compiled.

So, do we need std::rref() to make this things true?
I mean:
std::async(async_write,std::rref(std::move(socket)));

Daniel Krügler

unread,
Feb 9, 2014, 7:08:16 AM2/9/14
to std-pr...@isocpp.org
2014-02-09 <eulo...@live.com>:
No, std::reference_wrapper was carefully designed *not* to allow to
bind to temporaries. Your proposal would essentially conflict with
that policy.

I also don't see any advantage of adding rref, because std::async is
required to accept MoveConstructible arguments. It is possible that
the version of async that you are using has not properly implemented
the resolution of

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#2021

but that is just a guess.

- Daniel

eulo...@live.com

unread,
Feb 9, 2014, 8:02:17 PM2/9/14
to std-pr...@isocpp.org
No conflict with that policy.
For std::rref will not bind to that object. It will own the object(by moving the object from the original function) and then move the object to another function (in this example is async_write).

在 2014年2月9日星期日UTC+8下午8时08分16秒,Daniel Krügler写道:

David Krauss

unread,
Feb 9, 2014, 8:43:02 PM2/9/14
to std-pr...@isocpp.org
On Feb 10, 2014, at 9:02 AM, eulo...@live.com wrote:

No conflict with that policy.
For std::rref will not bind to that object. It will own the object(by moving the object from the original function) and then move the object to another function (in this example is async_write).

That wouldn't be a reference, then, but a container. Anyway, that semantic is what the linked DR specifies.

Below is my implementation of rref. I've only used it in a few cases, none of which survived refactoring. The potential for abuse probably makes it something better left in the personal toolboxes of power users.

It happily lives inside a bind object. The constructor takes an lvalue reference because the wrapper object is designed to persist, so it should not wrap a temporary. Currently C++ cannot express temporary-only classes, but I would leave it to a variant in such a category to wrap temporaries (can't think of a use case, though).

The getter functions effectively require it to be passed to an actual rvalue reference parameter; it will not implicitly convert to a prvalue. This pretty well guarantees that the receiver expects move semantics, despite no std::move ever being specified.

template< typename t >
struct rvalue_reference_wrapper : std::reference_wrapper< t > {
rvalue_reference_wrapper( t &o ) : std::reference_wrapper< t >( o ) {}
t &&get() const { return static_cast< t && >( std::reference_wrapper< t >::get() ); }
operator t&& () const { return get(); }
operator t& () const = delete;
};

template< typename t >
rvalue_reference_wrapper< t > rref( t &o ) { return { o }; }

Thomas Koeppe

unread,
Feb 9, 2014, 8:43:53 PM2/9/14
to std-pr...@isocpp.org, eulo...@live.com
Do you have an example implementation of "rref"?

eulo...@live.com

unread,
Feb 10, 2014, 4:14:21 AM2/10/14
to std-pr...@isocpp.org
How about this? Maybe a container.

template<typename t>
class rvalue_reference_wrapper
{
    t rrw;
public:
    rvalue_reference_wrapper(t&& r):rrw(std::move(r)){}
    rvalue_reference_wrapper(const rvalue_reference_wrapper&)=delete;
    rvalue_reference_wrapper& operator=(const rvalue_reference_wrapper&)=delete;
    rvalue_reference_wrapper(rvalue_reference_wrapper&&)=default;
    rvalue_reference_wrapper& operator=(rvalue_reference_wrapper&&)=default;
    t&& get(){return std::move(rrw);}
    operator t&&(){return std::move(rrw);}
};
 
template<typename t>
rvalue_reference_wrapper<t> rref(t&& r)
{
    return rvalue_reference_wrapper<t>(static_cast<t&&>(r));
}

在 2014年2月10日星期一UTC+8上午9时43分02秒,David Krauss写道:

Stack Machine

unread,
Feb 10, 2014, 3:08:41 PM2/10/14
to std-pr...@isocpp.org, eulo...@live.com
The above problem can be solved by simply moving the value and then taking it by lvalue reference within the functions. You can then later on move it if you want to. Allthough I have to agree it's a bit unintuitive, I don't see a problem with that.

David Krauss

unread,
Feb 11, 2014, 1:32:09 AM2/11/14
to std-pr...@isocpp.org
To reiterate, there's no problem in the first place, in a compiler implementing the resolution of DR 2021. The solution is a simple upgrade (or complain to your vendor).

Providing an rvalue argument the to bind or async is incompatible with receiving an lvalue reference argument. Remember that move does nothing by itself and it's generally incorrect to assume ownership of an lvalue reference parameter.

See the DR.
Reply all
Reply to author
Forward
0 new messages