[operators] A modern SFINAE-based version of boost::operators?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
32 messages Options
12
Reply | Threaded
Open this post in threaded view
|

[operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
Peter Sommerlad, committee member and C++Now presenter who often proposes
additions to fill in  holes in the standard library, asked me:

Are you aware of anybody who tried to provide a boost::operators style of
automatically providing additional operators with a single base class that
through SFINAE injects all possible operators based on the ones defined in
the template parameter? This won't give you the control of the current
boost::operators, but would be much easier to teach.

For example

struct Me : make_operators_for<Me>{
Me& operator+=(Me const&);       // You get +
bool operator<(Me const&) const; // You get all relops (<=> will make that
obsolete)
Me& operator++();                // you get postfix
//etc.
};

Today we have the facilities and compilers to make that happen.

What do you think? Who should I ask?

Anyone doing any work on operators or have any thoughts about updating
boost::operators?

--Beman

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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
I for one would be grateful for work on this. Particularly if it also
automatically manufactures move-aware versions of binary operators.

eg:

Foo&& operator+(Foo&& l, Foo const& r) { return std::move(l += r); }
Foo operator+(Foo const& l, Foo const& r) { return l += r; return l; }



On 13 November 2017 at 15:20, Beman Dawes via Boost <[hidden email]>
wrote:

> Peter Sommerlad, committee member and C++Now presenter who often proposes
> additions to fill in  holes in the standard library, asked me:
>
> Are you aware of anybody who tried to provide a boost::operators style of
> automatically providing additional operators with a single base class that
> through SFINAE injects all possible operators based on the ones defined in
> the template parameter? This won't give you the control of the current
> boost::operators, but would be much easier to teach.
>
> For example
>
> struct Me : make_operators_for<Me>{
> Me& operator+=(Me const&);       // You get +
> bool operator<(Me const&) const; // You get all relops (<=> will make that
> obsolete)
> Me& operator++();                // you get postfix
> //etc.
> };
>
> Today we have the facilities and compilers to make that happen.
>
> What do you think? Who should I ask?
>
> Anyone doing any work on operators or have any thoughts about updating
> boost::operators?
>
> --Beman
>
> _______________________________________________
> 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
|

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
of course I mean:

Foo operator+(Foo l, Foo const& r) { return l += r; return l; }

in the second version.


On 13 November 2017 at 16:05, Richard Hodges <[hidden email]> wrote:

> I for one would be grateful for work on this. Particularly if it also
> automatically manufactures move-aware versions of binary operators.
>
> eg:
>
> Foo&& operator+(Foo&& l, Foo const& r) { return std::move(l += r); }
> Foo operator+(Foo const& l, Foo const& r) { return l += r; return l; }
>
>
>
> On 13 November 2017 at 15:20, Beman Dawes via Boost <[hidden email]
> > wrote:
>
>> Peter Sommerlad, committee member and C++Now presenter who often proposes
>> additions to fill in  holes in the standard library, asked me:
>>
>> Are you aware of anybody who tried to provide a boost::operators style of
>> automatically providing additional operators with a single base class that
>> through SFINAE injects all possible operators based on the ones defined in
>> the template parameter? This won't give you the control of the current
>> boost::operators, but would be much easier to teach.
>>
>> For example
>>
>> struct Me : make_operators_for<Me>{
>> Me& operator+=(Me const&);       // You get +
>> bool operator<(Me const&) const; // You get all relops (<=> will make that
>> obsolete)
>> Me& operator++();                // you get postfix
>> //etc.
>> };
>>
>> Today we have the facilities and compilers to make that happen.
>>
>> What do you think? Who should I ask?
>>
>> Anyone doing any work on operators or have any thoughts about updating
>> boost::operators?
>>
>> --Beman
>>
>> _______________________________________________
>> 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
|

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
On 11/13/17 6:20 AM, Beman Dawes via Boost wrote:

> Peter Sommerlad, committee member and C++Now presenter who often proposes
> additions to fill in  holes in the standard library, asked me:
>
> Are you aware of anybody who tried to provide a boost::operators style of
> automatically providing additional operators with a single base class that
> through SFINAE injects all possible operators based on the ones defined in
> the template parameter? This won't give you the control of the current
> boost::operators, but would be much easier to teach.
>
> For example
>
> struct Me : make_operators_for<Me>{
> Me& operator+=(Me const&);       // You get +
> bool operator<(Me const&) const; // You get all relops (<=> will make that
> obsolete)
> Me& operator++();                // you get postfix
> //etc.
> };
>
> Today we have the facilities and compilers to make that happen.
>
> What do you think? Who should I ask?
>
> Anyone doing any work on operators or have any thoughts about updating
> boost::operators?

I'm pretty familiar with this.  I used boost operators to create
BOOST_STRONG_TYPE which a number of people liked.  As time went on, and
I wanted to make the serialization library more bullet proof, I fell out
of love with it because it generated all the numeric operators, thus
admitting errors (such as multiplying two object ids) I would have
preferred to be trapped at compile time. So I eventually removed the
usage of it.

This kind of thinking eventually has led me to my current major project
and likely last hurrah: my "Algebra" library.  This was the subject of
my presentation at CppCon 2016 “C++, Abstract Algebra and Practical
Applications" https://www.youtube.com/watch?v=632a-DMM5J0

I spent significant amount of time looking at boost operators and other
similar ideas for "automatically" adding "missing" operators.  The
problem which arises is trying to automatically determine which
operators are missing.  In the presentation I used the example of a
quantity length.  Given a length type and a corresponding + operator it
makes sense to "generate" a += operator.  But what about - ?  one can
take the difference of two lengths - but that operation is not
guaranteed to yield a valid value for length - so the automatic
operations wouldn't be a good choice.  A similar type - Position - would
have no problem with an automatically generated - operator.  So I
concluded that automatically generating "related" operators would turn
in to a minefield littered with lots of special cases, exceptions, weird
rules and a documentation nightmare.  I've turned to the implementation
of concepts of abstract algebra in terms of C++ as way to systematize
the selection, declaration and definition of operators in C++ for
specific types.  It is currently a work in progress.

The ultimate goal is to be able to specify algebraic types with a set of
attributes which would create all appropriate operators while trapping
any inappropriate usage.

Such a facility, in conjunction with Boost Units (enhanced with improved
easier to use documentation and perhaps some corresponding tweaks) would
provide the base for writing provably correct programs. These programs
would be written in terms of these strongly defined types such that it
is almost impossible to get wrong. (of course these would be a bitch to
compile - writing then normal crappy code is really fast and fun after
all).

An offshoot of this, which has been incredibly absorbing, is the safe
numerics library whose implemenation requires some of the ideas
mentioned above.  This is proceeding apace - it has required more time
and effort than anticipated.

Robert Ramey




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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
> On 13. Nov 2017, at 15:20, Beman Dawes via Boost <[hidden email]> wrote:
>
> Peter Sommerlad, committee member and C++Now presenter who often proposes
> additions to fill in  holes in the standard library, asked me:
>
> Are you aware of anybody who tried to provide a boost::operators style of
> automatically providing additional operators with a single base class that
> through SFINAE injects all possible operators based on the ones defined in
> the template parameter? This won't give you the control of the current
> boost::operators, but would be much easier to teach.

I'm the current maintainer of Boost.Operators and I heard about anyone working on that.

A few thoughts from my side:

I worked on other improvements, which ultimately went into its own library: <https://github.com/taocpp/operators>. There, I distinguish between commutative and non-commutative versions of some operators, as they allow me to provide additional optimisations (leading to fewer temporaries). This could not be done with a detection-style approach as the presence of an operator+ will not tell you whether or not it is commutative. It also plays some tricks returning rvalue-references which some people don't like (or consider dangerous), so it's not suitable for Boost.Operators.

Leaving that aside, I'd be willing to accept an *additional* base class for Boost.Operators just like you outlined. This *might* go into its own header as the current Boost.Operators library supports some quite ancient compilers and I don't want to break people's code. It also allows users to fall back to the existing approach if necessary, for example if the SFINAE-based code is too slow to compile. Or if you simply need more control of what exactly will be generated.

However, there will be a few questions: Shall we generate == if only < and > are provided? What about additional types? Think: x < 0 - shall we detect/generate them as well? Maybe something like this:

struct Me : make_operators_for<Me,int,double> { ... };

would try to detect Me==Me, Me==int and Me==double. But what if there is only one Me==long? Shall we detect the exact signature or if it is callable with the given parameters?

That said, I think it is not a straight-forward task and I'm not sure if it is worth it, but you or anyone else: Feel free to work on it and we'll see if it turns out fit for inclusion into Boost.Operators.



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

signature.asc (243 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
> On 13. Nov 2017, at 17:26, Daniel Frey via Boost <[hidden email]> wrote:

>
>> On 13. Nov 2017, at 15:20, Beman Dawes via Boost <[hidden email]> wrote:
>>
>> Peter Sommerlad, committee member and C++Now presenter who often proposes
>> additions to fill in  holes in the standard library, asked me:
>>
>> Are you aware of anybody who tried to provide a boost::operators style of
>> automatically providing additional operators with a single base class that
>> through SFINAE injects all possible operators based on the ones defined in
>> the template parameter? This won't give you the control of the current
>> boost::operators, but would be much easier to teach.
>
> I'm the current maintainer of Boost.Operators and I heard about anyone working on that.
Above sentence is missing a "haven't": I haven't heard of anyone working on that.



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

signature.asc (243 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
I am working on a proposal for the next committee meeting that would
generate more of these operators. We recently voted in a feature for the
comparison operators: the user defines `operator<=>` and gets all current
comparison operators generated automatically. I will be sure to post my
paper to this list for feedback prior to the mailing deadline. My paper
will include a fairly comprehensive rationale for the design, which will be
different from Boost.Operators. It has the advantage of needing only to
work with code built against the latest standard, and it has language
support, and it has the "disadvantage" of being done by default instead of
being explicitly requested by the user, which obviously has slightly
different design constraints.

On Mon, Nov 13, 2017 at 9:46 AM, Daniel Frey via Boost <
[hidden email]> wrote:

> > On 13. Nov 2017, at 17:26, Daniel Frey via Boost <[hidden email]>
> wrote:
> >
> >> On 13. Nov 2017, at 15:20, Beman Dawes via Boost <[hidden email]>
> wrote:
> >>
> >> Peter Sommerlad, committee member and C++Now presenter who often
> proposes
> >> additions to fill in  holes in the standard library, asked me:
> >>
> >> Are you aware of anybody who tried to provide a boost::operators style
> of
> >> automatically providing additional operators with a single base class
> that
> >> through SFINAE injects all possible operators based on the ones defined
> in
> >> the template parameter? This won't give you the control of the current
> >> boost::operators, but would be much easier to teach.
> >
> > I'm the current maintainer of Boost.Operators and I heard about anyone
> working on that.
>
> Above sentence is missing a "haven't": I haven't heard of anyone working
> on that.
>
>
>
> _______________________________________________
> 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
|

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
Dear Daniel,

> On 13. Nov 2017, at 17:26, Daniel Frey via Boost <[hidden email]> wrote:
>
> I worked on other improvements, which ultimately went into its own library: <https://github.com/taocpp/operators>. There, I distinguish between commutative and non-commutative versions of some operators, as they allow me to provide additional optimisations (leading to fewer temporaries). This could not be done with a detection-style approach as the presence of an operator+ will not tell you whether or not it is commutative. It also plays some tricks returning rvalue-references which some people don't like (or consider dangerous), so it's not suitable for Boost.Operators.

when I was looking into operators for the histogram library, I also considered Boost.Operators and I also looked into your taocpp/operators.

I was wondering why are the rvalue-optimised versions of operators are not already part of Boost.Operators? I don't know what kind of tricks you are talking about, surely there must be rvalue-enabled versions that are standard compliant and safe, like the implementations that Richard Hodges mentioned. This seems like a straight-forward improvement of Boost.Operators that doesn't break old code. Or am I missing something?

Best regards,
Hans

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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
> On 14. Nov 2017, at 09:43, Hans Dembinski <[hidden email]> wrote:

>
> Dear Daniel,
>
>> On 13. Nov 2017, at 17:26, Daniel Frey via Boost <[hidden email]> wrote:
>>
>> I worked on other improvements, which ultimately went into its own library: <https://github.com/taocpp/operators>. There, I distinguish between commutative and non-commutative versions of some operators, as they allow me to provide additional optimisations (leading to fewer temporaries). This could not be done with a detection-style approach as the presence of an operator+ will not tell you whether or not it is commutative. It also plays some tricks returning rvalue-references which some people don't like (or consider dangerous), so it's not suitable for Boost.Operators.
>
> when I was looking into operators for the histogram library, I also considered Boost.Operators and I also looked into your taocpp/operators.
>
> I was wondering why are the rvalue-optimised versions of operators are not already part of Boost.Operators? I don't know what kind of tricks you are talking about, surely there must be rvalue-enabled versions that are standard compliant and safe, like the implementations that Richard Hodges mentioned. This seems like a straight-forward improvement of Boost.Operators that doesn't break old code. Or am I missing something?
The "problem" is that returning rvalue-references will lead to dangling references in two cases.

Before looking at those cases, consider a commutative operator+ (abbreviated version):

T   operator+( const T&  lhs, const T&  rhs ) { T nrv( lhs ); nrv += rhs; return nrv; } // v1
T&& operator+(       T&& lhs, const T&  rhs ) { lhs += rhs; return std::move( lhs ); } // v2
T&& operator+( const T&  lhs,       T&& rhs ) { rhs += lhs; return std::move( rhs ); } // v3, remember: we assume a commutative +
T&& operator+(       T&& lhs,       T&& rhs ) { lhs += rhs; return std::move( lhs ); } // v4

now consider using it:

const T t1, t2, t3, t4; // some values
const T t = t1 + ( t2 + t3 ) + t4;

The last line creates a temporary T for t2+t3 with v1, then calls v3 which calls += on the temporary, then v2 which again calls += on the temporary. Finally, the temporary is moved into t. So far, so good: Intermediate temporaries are only destroyed at the end of a full expression. This also means, that calling a function will work as expected. Given:

void f( const T& ); // some function which wants above T

calling

f( t1 + ( t2 + t3 ) + t4 ); // fine, creates a single temporary

works as it should.

Now for the two cases where you can create a dangling reference:

a) Explicitly binding to a reference "to prolong the lifetime of the temporary".

This happens if you write

const T& t = t1 + ( t2 + t3 ) + t4;

As the last operator+ return an rvalue reference instead of an rvalue, the "const T& t =" does not bind to a temporary. The intermediate temporary created by (v2+v3) is destroyed at the end of the expression, hence t is now a dangling reference. Oops.

This case is explicit, so you were basically asking for it. In my opinion it is user-error, since you expected a temporary but you haven't checked. Some people disagree and say that every class must make sure that this always works - basically forcing methods (especially operators) to always return an ralue / a temporary. This would effectively disallow these optimisations.

As I can not know whether people used this in existing code, it is also not backwards compatible. This is the reason why I decided to put this into a new library and kept it out of Boost.Operators.

b) The second case is implicit: Using a range-based for loop. Consider T being a container (or container-like) class and:

for ( const auto& element : t1 + ( t2 + t3 ) + t4 ) { ... }

This will also not work as the intermediate temporary created by (t2+t3) and which is passed to the range-based for loop is destroyed *before* the loop is executed. A solution is to actually store the value first:

const auto t = t1 + ( t2 + t3 ) + t4;
for ( const auto& element : t ) { ... }

or maybe with C++20:

for ( const auto t = t1 + ( t2 + t3 ) + t4; const auto& element : t ) { ... } // Yuck. Why??

I still think that a range-based for loop should treat the expression similar to a function call, the intermediate temporaries should only be destroyed at the end of the full loop. Sadly, all my attempts to convince others lead to nowhere.

I hope this explains what I have done, why I chose to put it in its own library and not into Boost.Operators and what is controversial about it.

Best regards,
Daniel



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

signature.asc (243 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
Le 13/11/2017 à 15:20, Beman Dawes via Boost a écrit :

> Peter Sommerlad, committee member and C++Now presenter who often proposes
> additions to fill in  holes in the standard library, asked me:
>
> Are you aware of anybody who tried to provide a boost::operators style of
> automatically providing additional operators with a single base class that
> through SFINAE injects all possible operators based on the ones defined in
> the template parameter? This won't give you the control of the current
> boost::operators, but would be much easier to teach.
>
> For example
>
> struct Me : make_operators_for<Me>{
> Me& operator+=(Me const&);       // You get +
> bool operator<(Me const&) const; // You get all relops (<=> will make that
> obsolete)
> Me& operator++();                // you get postfix
> //etc.
> };
>
> Today we have the facilities and compilers to make that happen.
>
> What do you think? Who should I ask?
>
> Anyone doing any work on operators or have any thoughts about updating
> boost::operators?
>
I find all or nothing approach innovative. But not all the innovations
are good. I've always preferred to master the proposed interface? so I
prefer to request for set of operators explicitly, e.g. I could ask for
arithmetic_operators.

Note that the default don't map what we could always expect. E.g. when
we are defining a counter, not all the operations supported by an number
are desired (See e.g. chrono::duration, where we want to add durations
but not to multiply them.
I've been working since a long time on strong types wrapper that could
inherit some of the operations of the underlying type,but not all.
The design of the valid operations is not easy. See [1] for some
examples requiring a restricted number of operations.

While the scope of the PO subject is different (defining operations from
other operation on the same type), I believe that it is worth
considering some strong types as concrete examples, and I don't believe
there is a single case where we want all the operations.
So before going with the all or nothing approach I would like to see
some concrete examples where this will be useful.


Best,
Vicente
[1] Strong types POC

https://github.com/viboes/std-make/tree/master/include/experimental/fundamental/v3/strong 

     https://github.com/viboes/std-make/tree/master/example/strong
     https://github.com/viboes/std-make/tree/master/test/strong


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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
Le 14/11/2017 à 02:38, David Stone via Boost a écrit :

> I am working on a proposal for the next committee meeting that would
> generate more of these operators. We recently voted in a feature for the
> comparison operators: the user defines `operator<=>` and gets all current
> comparison operators generated automatically. I will be sure to post my
> paper to this list for feedback prior to the mailing deadline. My paper
> will include a fairly comprehensive rationale for the design, which will be
> different from Boost.Operators. It has the advantage of needing only to
> work with code built against the latest standard, and it has language
> support, and it has the "disadvantage" of being done by default instead of
> being explicitly requested by the user, which obviously has slightly
> different design constraints.
Hi,

I'm curious on knowing more on your approach.

Note that the operator<==> return something that states what kind of
order we want to define, and in this sense this is an explicit mapping.
I like the explicit mapping and find the implicit one could be a source
of surprises.

I'm realy interested on the derivation of functions from other in
general. If you need a reader with a another point of view, please,
contact me.

Best,
Vicente
>
>


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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
On 11/14/2017 1:16 PM, Daniel Frey via Boost wrote:

>> On 14. Nov 2017, at 09:43, Hans Dembinski <[hidden email]> wrote:
>>
>> Dear Daniel,
>>
>>> On 13. Nov 2017, at 17:26, Daniel Frey via Boost <[hidden email]> wrote:
>>>
>>> I worked on other improvements, which ultimately went into its own library: <https://github.com/taocpp/operators>. There, I distinguish between commutative and non-commutative versions of some operators, as they allow me to provide additional optimisations (leading to fewer temporaries). This could not be done with a detection-style approach as the presence of an operator+ will not tell you whether or not it is commutative. It also plays some tricks returning rvalue-references which some people don't like (or consider dangerous), so it's not suitable for Boost.Operators.
>>
>> when I was looking into operators for the histogram library, I also considered Boost.Operators and I also looked into your taocpp/operators.
>>
>> I was wondering why are the rvalue-optimised versions of operators are not already part of Boost.Operators? I don't know what kind of tricks you are talking about, surely there must be rvalue-enabled versions that are standard compliant and safe, like the implementations that Richard Hodges mentioned. This seems like a straight-forward improvement of Boost.Operators that doesn't break old code. Or am I missing something?
>
> The "problem" is that returning rvalue-references will lead to dangling references in two cases.
>
> Before looking at those cases, consider a commutative operator+ (abbreviated version):
>
> T   operator+( const T&  lhs, const T&  rhs ) { T nrv( lhs ); nrv += rhs; return nrv; } // v1
> T&& operator+(       T&& lhs, const T&  rhs ) { lhs += rhs; return std::move( lhs ); } // v2
> T&& operator+( const T&  lhs,       T&& rhs ) { rhs += lhs; return std::move( rhs ); } // v3, remember: we assume a commutative +
> T&& operator+(       T&& lhs,       T&& rhs ) { lhs += rhs; return std::move( lhs ); } // v4

My understanding may be deficient but I would never assume that adding
two values would change either of the values in any way, even if one or
more of those values were rvalue references. Please tell me what I am
missing and I will gladly admit my C++ ignorance in this matter if that
is the case.

snipped...


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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
> My understanding may be deficient but I would never assume that adding two values would change either of the values in any way, even if one or more of those values were rvalue references. Please tell me what I am missing and I will gladly admit my C++ ignorance in this matter if that is the case.

If you pass in an rvalue reference, you *do* expect it to be modified and you do not expect it to be accessible afterwards. Given:

void f( std::vector<int>&& v ) { ... }

and calling

std::vector< int > v = ...;
f(v);

why do you expect that v has not been changed or that you can still use it?

Even "adding" the values doesn't change that. If you give me an rvalue reference, I'm (mostly) free to destroy it in any way I like :)

And yes, in a moved-from state you are still allowed to re-assign the value. So, I think I am expecting users of those operators (taocpp/operators) to use value-semantics from a user's perspective. You don't write

int r = std::move(1) + std::move(2); just because you don't need 1 and 2 afterwards.



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

signature.asc (243 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
On 11/14/2017 2:35 PM, Daniel Frey via Boost wrote:
>> My understanding may be deficient but I would never assume that adding two values would change either of the values in any way, even if one or more of those values were rvalue references. Please tell me what I am missing and I will gladly admit my C++ ignorance in this matter if that is the case.
>
> If you pass in an rvalue reference, you *do* expect it to be modified and you do not expect it to be accessible afterwards.

OK, Point conceded.

> Given:
>
> void f( std::vector<int>&& v ) { ... }
>
> and calling
>
> std::vector< int > v = ...;
> f(v);

I think you meant

f(std::move(v));

>
> why do you expect that v has not been changed or that you can still use it?

Agreed.

>
> Even "adding" the values doesn't change that. If you give me an rvalue reference, I'm (mostly) free to destroy it in any way I like :)

Ok. It does seem odd to "change" a value passed in an addition, but I do
see that changing an rvalue reference should be allowable, since it is a
temporary.

>
> And yes, in a moved-from state you are still allowed to re-assign the value. So, I think I am expecting users of those operators (taocpp/operators) to use value-semantics from a user's perspective. You don't write
>
> int r = std::move(1) + std::move(2); just because you don't need 1 and 2 afterwards.

Agreed.


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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
> On 14. Nov 2017, at 22:32, Edward Diener via Boost <[hidden email]> wrote:

>
> On 11/14/2017 2:35 PM, Daniel Frey via Boost wrote:
>>> My understanding may be deficient but I would never assume that adding two values would change either of the values in any way, even if one or more of those values were rvalue references. Please tell me what I am missing and I will gladly admit my C++ ignorance in this matter if that is the case.
>> If you pass in an rvalue reference, you *do* expect it to be modified and you do not expect it to be accessible afterwards.
>
> OK, Point conceded.
>
>> Given:
>> void f( std::vector<int>&& v ) { ... }
>> and calling
>> std::vector< int > v = ...;
>> f(v);
>
> I think you meant
>
> f(std::move(v));
D'oh! Of course. Thanks for reading what I meant instead of reading what I wrote :)



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

signature.asc (243 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
On 15/11/2017 07:16, Daniel Frey wrote:
> Before looking at those cases, consider a commutative operator+ (abbreviated version):
>
> T   operator+( const T&  lhs, const T&  rhs ) { T nrv( lhs ); nrv += rhs; return nrv; } // v1
> T&& operator+(       T&& lhs, const T&  rhs ) { lhs += rhs; return std::move( lhs ); } // v2
> T&& operator+( const T&  lhs,       T&& rhs ) { rhs += lhs; return std::move( rhs ); } // v3, remember: we assume a commutative +
> T&& operator+(       T&& lhs,       T&& rhs ) { lhs += rhs; return std::move( lhs ); } // v4

Given that NRVO is mandatory now, isn't it just as efficient and more
correct to declare these as:

T operator+( const T&  lhs, const T&  rhs ) { T nrv( lhs ); nrv += rhs;
return nrv; } // v1
T operator+(       T&& lhs, const T&  rhs ) { lhs += rhs; return lhs; }
// v2
T operator+( const T&  lhs,       T&& rhs ) { rhs += lhs; return rhs; }
// v3, remember: we assume a commutative +
T operator+(       T&& lhs,       T&& rhs ) { lhs += rhs; return lhs; }
// v4

(You could save a little typing by using "return lhs += rhs;" but that's
probably not a good idea as you're left to the whims of compiler
inlining whether it triggers some kind of RVO or not.)

Unless I'm missing something?

> a) Explicitly binding to a reference "to prolong the lifetime of the temporary".
>
> This happens if you write
>
> const T& t = t1 + ( t2 + t3 ) + t4;
>
> As the last operator+ return an rvalue reference instead of an rvalue, the "const T& t =" does not bind to a temporary. The intermediate temporary created by (v2+v3) is destroyed at the end of the expression, hence t is now a dangling reference. Oops.

The above would fix this, and your other case.


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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
> If you pass in an rvalue reference, you *do* expect it to be modified and you do not expect it to be accessible afterwards.

That's only an until-so-far STL convention.

In my own code I treat rvalue references as "this may or may not be
consumed" parameter. So the function may consume the input wholly,
leaving it in some zombie state. Or it may leave it as is. Obviously the
return type says what happened.

This lets you write filtering functions such as:

SomeObj foo.
filter_a(std::move(foo));
filter_b(std::move(foo));
filter_c(std::move(foo));
filter_d(std::move(foo));

Now some will quite rightly object to using std::move when I mean "maybe
move". I should really type out:

filter_a(static_cast<SomeObj &&>(foo));
filter_b(static_cast<SomeObj &&>(foo));
filter_c(static_cast<SomeObj &&>(foo));
filter_d(static_cast<SomeObj &&>(foo));

But it takes too long to type, so I use std::move.

In case anyone thinks I am being weird on this, I was taught to think of
rvalue ref parameter inputs this way by Howard Hinnant. It's been a
useful technique to know. I just wish clang-tidy didn't warn on this
technique so readily.

Niall

--
ned Productions Limited Consulting
http://www.nedproductions.biz/ http://ie.linkedin.com/in/nialldouglas/


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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
On 11/15/17 03:04, Gavin Lambert via Boost wrote:

> Given that NRVO is mandatory now, <snip>

It is? Since when? AFAIK C++17 makes RVO mandatory, but not NRVO.

Thanks,
Gevorg


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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
On 15/11/2017 19:27, Gevorg Voskanyan wrote:
> On 11/15/17 03:04, Gavin Lambert wrote:
>
>> Given that NRVO is mandatory now, <snip>
>
> It is? Since when? AFAIK C++17 makes RVO mandatory, but not NRVO.

True, I was thinking of a different case and misspoke.  The rest of the
post still stands though; any optimiser worth its salt should be able to
apply NVRO there and elide most if not all of the copies, and it should
be safer without sacrificing performance.

Granted that I have not actually measured this, and so might end up
surprised.


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

Re: [operators] A modern SFINAE-based version of boost::operators?

Boost - Dev mailing list
Dear Gavin,

> On 15. Nov 2017, at 07:58, Gavin Lambert via Boost <[hidden email]> wrote:
>
> On 15/11/2017 19:27, Gevorg Voskanyan wrote:
>> On 11/15/17 03:04, Gavin Lambert wrote:
>>> Given that NRVO is mandatory now, <snip>
>> It is? Since when? AFAIK C++17 makes RVO mandatory, but not NRVO.
>
> True, I was thinking of a different case and misspoke.  The rest of the post still stands though; any optimiser worth its salt should be able to apply NVRO there and elide most if not all of the copies, and it should be safer without sacrificing performance.
>
> Granted that I have not actually measured this, and so might end up surprised.


I played around with the two versions of operators, the one returning rvalue references and the ones you suggested that might apply NVRO.

https://github.com/HDembinski/testing_grounds/blob/master/test/test_fast_operators.cpp <https://github.com/HDembinski/testing_grounds/blob/master/test/test_fast_operators.cpp>

On Apple Clang 9.0.0, NVRO does not seem to work, but perhaps I am not tracking this correctly. I use this class to track copying calls:

static unsigned ctor_count = 0;

struct A {
    A() { ++ctor_count; }
    A(const A&) { ++ctor_count; }
    A& operator=(const A&) { ++ctor_count; return *this; }
    A(A&&) {}
    A& operator=(A&&) { return *this; }
    A& operator+=(const A&) { return *this; }
};

Best regards,
Hans

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