[move] BOOST_RV_REF(TypeWithoutMoveEmulation) parameters

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[move] BOOST_RV_REF(TypeWithoutMoveEmulation) parameters

Boost - Dev mailing list
Hi,

I'd like to use BOOST_RV_REF, with both C++98 and C++11 compilers, for some sink-functions, with types that are not "move-enabled". I.e. types that the sink can "consume"/"move from" by other means (swapping, calling .release(), ...). Some of them I can - eventually - change to be fully move-enabled, others I can not (e.g. STL classes).

I just assumed that this was possible by simply passing the argument with boost::move(arg). Apparently it's not though, because boost::move will return a plain T& for types without move emulation.
For the time being I have defined my own helper function template "move_any" that will always return a rv<T>&.

Is there such a function that I missed? And if not, would you think it'd make sense to provide one (I certainly think it would)?

Regards,
Paul Groke


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [move] BOOST_RV_REF(TypeWithoutMoveEmulation) parameters

Boost - Dev mailing list
On 20/05/2017 02:16, Groke, Paul via Boost wrote:

> I'd like to use BOOST_RV_REF, with both C++98 and C++11 compilers,
> for some sink-functions, with types that are not "move-enabled". I.e.
> types that the sink can "consume"/"move from" by other means
> (swapping, calling .release(), ...). Some of them I can - eventually
> - change to befully move-enabled, others I can not (e.g. STL classes).
>
> I just assumed that this was possible by simply passing the argument
> with boost::move(arg). Apparently it's not though, because boost::move
> will return a plain T& for types without move emulation.
> For the time being I have defined my own helper function template
> "move_any" that will always return a rv<T>&.
>
> Is there such a function that I missed? And if not, would you think it'd make sense to provide one (I certainly think it would)?
>
> Regards,
> Paul Groke
>
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
>



_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [move] BOOST_RV_REF(TypeWithoutMoveEmulation) parameters

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
On 20/05/2017 02:16, Groke, Paul wrote:

> I'd like to use BOOST_RV_REF, with both C++98 and C++11 compilers,
> for some sink-functions, with types that are not "move-enabled". I.e.
> types that the sink can "consume"/"move from" by other means
> (swapping, calling .release(), ...). Some of them I can - eventually
> - change to be fully move-enabled, others I can not (e.g. STL
> classes).
>
> I just assumed that this was possible by simply passing the argument
> with boost::move(arg). Apparently it's not though, because
> boost::move  will return a plain T& for types without move emulation.
> For the time being I have defined my own helper function template
> "move_any" that will always return a rv<T>&.
>
> Is there such a function that I missed? And if not, would you think
> it'd make sense to provide one (I certainly think it would)?

Apologies for the prior blank reply; accidentally fat-fingered the Send
button.

I don't think this makes sense.  The Boost.Move emulation library is
exactly that -- an as-close-to-possible *emulation* of
rvalue-reference-based C++11 move for pre-C++11 compilers.  As such it
is naturally designed for modification of the type-to-be-moved (it
requires adding move constructors etc as applicable).

Additionally, when actually compiled in C++11 it gracefully upgrades to
actual rvalue references -- as such the rv<T> class disappears entirely;
this is an implementation detail and you're not supposed to use it
outside of the macros in the documented interface of Boost.Move.  (Also,
I have grave doubts that returning one by reference could be correct
code, as they're typically locally constructed IIRC.)

If you want to write some generic code around swap(), then do that; this
exists for both C++11 and prior.

Also, be careful with move.  It's a shiny new toy so people are excited
to play with it, but if not used carefully (*especially* with a
non-C++11 STL) it can easily lead to incorrect behaviour or degraded
performance.  Learn both when and when *not* to use it.


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [move] BOOST_RV_REF(TypeWithoutMoveEmulation) parameters

Boost - Dev mailing list
On Monday, 22. Mai 2017 03:21, Gavin Lambert wrote:

> > I just assumed that this was possible by simply passing the argument
> > with boost::move(arg). Apparently it's not though, because boost::move
> > will return a plain T& for types without move emulation.
> > For the time being I have defined my own helper function template
> > "move_any" that will always return a rv<T>&.
> >
> > Is there such a function that I missed? And if not, would you think
> > it'd make sense to provide one (I certainly think it would)?
>
> Apologies for the prior blank reply; accidentally fat-fingered the Send button.
>
> I don't think this makes sense.  The Boost.Move emulation library is exactly
> that -- an as-close-to-possible *emulation* of rvalue-reference-based C++11
> move for pre-C++11 compilers.  As such it is naturally designed for
> modification of the type-to-be-moved (it requires adding move constructors
> etc as applicable).
>
> Additionally, when actually compiled in C++11 it gracefully upgrades to actual
> rvalue references -- as such the rv<T> class disappears entirely; this is an
> implementation detail and you're not supposed to use it outside of the
> macros in the documented interface of Boost.Move.  (Also, I have grave
> doubts that returning one by reference could be correct code, as they're
> typically locally constructed IIRC.)

I'm sorry, I guess that was confusing. My "move_any" function does of course return an rvalue reference in >= C++11 mode. It just doesn't behave differently for types that are not move-enabled in C++98 mode. Regarding returning boost::rv by reference - I didn't invent that, that's exactly what Boost.Move does. It's a necessary hack to allow Boost.Move to work more or less transparently. I simply copied the definition of boost::move sans the "should I return boost::rv<T>& for this type" checks in C++98 mode.

> If you want to write some generic code around swap(), then do that; this
> exists for both C++11 and prior.

I want to write sink functions that can "consume" a value. They're not member functions of the class they're consuming. In C++11 I would use rvalue references for this. In C++98 I don't know any elegant way of expressing this. Of course I could write the function to take a normal lvalue reference, but that's not visible at the call site. If I use BOOST_RV_REF instead, then it becomes visible at the call site because the caller explicitly has to write "move", which IMO is a great improvement. Of course I could use my own helper type for this. But since everything (except the "move_any" function) is already there in Boost.Move, and I also want to fully move-enable some types in the future using Boost.Move (which would require interoperability between my own solution and Boost.Move), I'd like to use Boost.Move/BOOST_RV_REF for it.

As an example, given this C++11 code:

void Foo::StringSink(std::string&& s) { ... }
...
void Bar::SomeEventHandler() {
    this->foo->StringSink(std::move(this->stringMember)); // stringMember is never used after this point
}

I'd like to be able to emulate that in C++98 ala

void Foo::StringSink(BOOST_RV_REF(std::string) s) { ... }
...
void Bar::SomeEventHandler () {
    this->foo->StringSink(boost::move_any(this->stringMember)); // stringMember is never used after this point
}

Boost.Move allows me to do this, but only if the type passed to boost::move() is itself move enabled. Which IMO is an unnecessary restriction.

> Also, be careful with move.  It's a shiny new toy so people are excited to play
> with it, but if not used carefully (*especially* with a
> non-C++11 STL) it can easily lead to incorrect behaviour or degraded
> performance.  Learn both when and when *not* to use it.

I don't want to come across as confrontational, but ... what makes you think I don't know when and when not to use it?
I'm working with more or less performance critical code here. Not so much that I can warrant writing code that's very hard to write and very hard to understand for the sake of performance. Which is why I don't want to use T& for my sink parameters. But it's definitely code where I don't want to copy e.g. a std::string if I don't have to copy it. And there are quite a few places where I have to "move" strings (or objects containing strings) around, where I cannot use C++98 copy elision stuff.

And regarding implementation details: One of the reasons why I would want this to be implemented in Boost.Move is that I don't want my code to rely on the internals of Boost.Move.

Regards,
Paul Groke


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [move] BOOST_RV_REF(TypeWithoutMoveEmulation) parameters

Boost - Dev mailing list
> As an example, given this C++11 code:
>
> void Foo::StringSink(std::string&& s) { ... }
> ...
> void Bar::SomeEventHandler() {
>     this->foo->StringSink(std::move(this->stringMember)); // stringMember
is never used after this point
> }
>
> I'd like to be able to emulate that in C++98 ala
>
> void Foo::StringSink(BOOST_RV_REF(std::string) s) { ... }
> ...
> void Bar::SomeEventHandler () {
>     this->foo->StringSink(boost::move_any(this->stringMember)); //
stringMember is never used after this point
> }
> Boost.Move allows me to do this, but only if the type passed to
boost::move() is itself move enabled. Which IMO is an unnecessary
restriction.

In C++98 you can pass a parameter that is not movable (meaning, implements
internal boost::rv facility) to boost::move it will just send a reference
to it.
If the type doesn't implements boost::rv, I think you're stuck with copies
and such, so it's not an unnecessary restriction.

As for stl containers such as std::string or std::vector, you could use
boost::container::string (vector, etc.), they emulate move semantics for
C++98 compilers, and as far as I used them in my applications, in most
cases they outperform stl containers.

But the main drawback that comes with this workaround is the
interoperability with other APIs that use std::string (or other) because
they don't know boost::container, so you have to write more code that
handle this use case.

Regards
Danny

2017-05-22 10:44 GMT+02:00 Groke, Paul via Boost <[hidden email]>:

> On Monday, 22. Mai 2017 03:21, Gavin Lambert wrote:
> > > I just assumed that this was possible by simply passing the argument
> > > with boost::move(arg). Apparently it's not though, because boost::move
> > > will return a plain T& for types without move emulation.
> > > For the time being I have defined my own helper function template
> > > "move_any" that will always return a rv<T>&.
> > >
> > > Is there such a function that I missed? And if not, would you think
> > > it'd make sense to provide one (I certainly think it would)?
> >
> > Apologies for the prior blank reply; accidentally fat-fingered the Send
> button.
> >
> > I don't think this makes sense.  The Boost.Move emulation library is
> exactly
> > that -- an as-close-to-possible *emulation* of rvalue-reference-based
> C++11
> > move for pre-C++11 compilers.  As such it is naturally designed for
> > modification of the type-to-be-moved (it requires adding move
> constructors
> > etc as applicable).
> >
> > Additionally, when actually compiled in C++11 it gracefully upgrades to
> actual
> > rvalue references -- as such the rv<T> class disappears entirely; this
> is an
> > implementation detail and you're not supposed to use it outside of the
> > macros in the documented interface of Boost.Move.  (Also, I have grave
> > doubts that returning one by reference could be correct code, as they're
> > typically locally constructed IIRC.)
>
> I'm sorry, I guess that was confusing. My "move_any" function does of
> course return an rvalue reference in >= C++11 mode. It just doesn't behave
> differently for types that are not move-enabled in C++98 mode. Regarding
> returning boost::rv by reference - I didn't invent that, that's exactly
> what Boost.Move does. It's a necessary hack to allow Boost.Move to work
> more or less transparently. I simply copied the definition of boost::move
> sans the "should I return boost::rv<T>& for this type" checks in C++98 mode.
>
> > If you want to write some generic code around swap(), then do that; this
> > exists for both C++11 and prior.
>
> I want to write sink functions that can "consume" a value. They're not
> member functions of the class they're consuming. In C++11 I would use
> rvalue references for this. In C++98 I don't know any elegant way of
> expressing this. Of course I could write the function to take a normal
> lvalue reference, but that's not visible at the call site. If I use
> BOOST_RV_REF instead, then it becomes visible at the call site because the
> caller explicitly has to write "move", which IMO is a great improvement. Of
> course I could use my own helper type for this. But since everything
> (except the "move_any" function) is already there in Boost.Move, and I also
> want to fully move-enable some types in the future using Boost.Move (which
> would require interoperability between my own solution and Boost.Move), I'd
> like to use Boost.Move/BOOST_RV_REF for it.
>
> As an example, given this C++11 code:
>
> void Foo::StringSink(std::string&& s) { ... }
> ...
> void Bar::SomeEventHandler() {
>     this->foo->StringSink(std::move(this->stringMember)); // stringMember
> is never used after this point
> }
>
> I'd like to be able to emulate that in C++98 ala
>
> void Foo::StringSink(BOOST_RV_REF(std::string) s) { ... }
> ...
> void Bar::SomeEventHandler () {
>     this->foo->StringSink(boost::move_any(this->stringMember)); //
> stringMember is never used after this point
> }
>
> Boost.Move allows me to do this, but only if the type passed to
> boost::move() is itself move enabled. Which IMO is an unnecessary
> restriction.
>
> > Also, be careful with move.  It's a shiny new toy so people are excited
> to play
> > with it, but if not used carefully (*especially* with a
> > non-C++11 STL) it can easily lead to incorrect behaviour or degraded
> > performance.  Learn both when and when *not* to use it.
>
> I don't want to come across as confrontational, but ... what makes you
> think I don't know when and when not to use it?
> I'm working with more or less performance critical code here. Not so much
> that I can warrant writing code that's very hard to write and very hard to
> understand for the sake of performance. Which is why I don't want to use T&
> for my sink parameters. But it's definitely code where I don't want to copy
> e.g. a std::string if I don't have to copy it. And there are quite a few
> places where I have to "move" strings (or objects containing strings)
> around, where I cannot use C++98 copy elision stuff.
>
> And regarding implementation details: One of the reasons why I would want
> this to be implemented in Boost.Move is that I don't want my code to rely
> on the internals of Boost.Move.
>
> Regards,
> Paul Groke
>
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/
> mailman/listinfo.cgi/boost
>

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [move] BOOST_RV_REF(TypeWithoutMoveEmulation) parameters

Boost - Dev mailing list
danny kabrane wrote:

> As for stl containers such as std::string or std::vector, you could use
> boost::container::string (vector, etc.), they emulate move semantics for
> C++98 compilers, and as far as I used them in my applications, in most
> cases they outperform stl containers.

Thanks for the tip. I didn't know about boost::container::string.

> But the main drawback that comes with this workaround is the
> interoperability with other APIs that use std::string (or other) because they
> don't know boost::container, so you have to write more code that handle
> this use case.

Yes. Which is why we probably won't be able to use boost::container::string. Anyway it's good to know about the possibility.

Regards,
Paul Groke


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Loading...