Date: Tue, 1 Sep 2020 18:07:59 -0400

>

>

> Am 01.09.2020 um 02:51 schrieb Jefferson Carpenter via Std-Discussion:

> > On 8/30/2020 12:35 AM, Jeremy Ong via Std-Discussion wrote:

> >> Perhaps a type trait is a suitable alternative for this (as opposed to

> >> introducing yet another keyword that decorates a function signature).

> >> For

> >> example: https://godbolt.org/z/ecaro9

> >

>

This operator+ has "too perfect forwarding" and can break many other

operators. Here it breaks an ordinary std::string concatenation:

https://godbolt.org/z/bvnd9f

> > +1

> >

> > Also use std::enable_if instead of a static_assert in the function

> > body. This takes advantage of SFINAE so that you can write

> > `does_commute` for some types, `does_anticommute` for other types, etc.

> >

> > https://godbolt.org/z/7ssTjW

> >

>

This isn't quite right. The "template <..., std::enable_if_t<...>>" does

take the template out of overload resolution when the enable_if expression

is false. But when the expression is true, it declares a non-type template

parameter with type void, which is not allowed. The godbolt link doesn't

notice the issue because check_commute now calls the original specific

operator+(complex, float), not the template. One simple fix: Make the type

int instead, and add a default template argument, as in "template <...,

std::enable_if_t<..., int> = 0>". Demo: https://godbolt.org/z/hseceW

I also added std::forward for perfect forwarding. This might help for an

underlying function like X operator+(X x, const Y& y) { x += y; return x; }

> >>

> >> On Sat, Aug 29, 2020 at 6:03 PM Tobias W. via Std-Discussion <

> >> std-discussion_at_[hidden]> wrote:

> >>

> >>> Hi everyone!

> >>> I am coming with a mathematical and embedded systems background and

> >>> there is something that bothered me since I started programming.

> >>> Firstly, I would like to explain the problem with an example that

> >>> occurs

> >>> often in slightly different but similar ways.

> >>> Secondly, I will propose a possible solution.

> >>> Of course, I would love to hear your thoughts.

> >>> So let's imagine we have three classes.

> >>> class Real{

> >>> double value;

> >>> ...

> >>>

> >>> };

> >>>

> >>> class Imag{

> >>> double value;

> >>> ...

> >>>

> >>> }

> >>>

> >>> class Complex{

> >>> double Im;

> >>> double Re;

> >>> ...

> >>>

> >>> };

> >>>

> >>> Then if I was to write functions, for example, an add function or

> >>> operator+ and would like to add them in all possible permutations of

> >>> arguments.

> >>> This means, that I would have to write all those following functions,

> >>> just to add them:

> >>>

> >>> Complex operator+ (Real a, Imag b);

> >>> Complex operator+ (Imag b, Real a); // Mirrored function

> >>> Complex operator+ (Real a, Complex b);

> >>> Complex operator+ ( Complex b, Real a); //Mirrored function

> >>> Complex operator+ (Imag a, Complex b);

> >>> Complex operator+ ( Complex b, Imag a); //Mirrored function

> >>>

> >>> From a mathematical point of view, all mirrored functions are

> >>> obsolete,

> >>> because the intent has already been stated in the function above.

> >>> Furthermore, each mirrored function will use additional program memory

> >>> and this can become an issue on embedded devices.

> >>> Therefore I would like to introduce the idea of the expression

> >>> "commutative" that can be added to functions.

> >>> The commutative expression will tell the compiler that he can switch

> >>> the

> >>> parameters that will be passed to a function.

> >>> Following this, the keyword will only be allowed for functions that

> >>> possess two and only two parameters.

> >>> Then the example from above may look something like this:

> >>>

> >>> commutative Complex operator+ (Real a, Imag b);

> >>> commutative Complex operator+ (Real a, Complex b);

> >>> commutative Complex operator+ (Imag a, Complex b);

> >>>

> >>> If the compiler comes across a statement like below, he is allowed to

> >>> restructure the code.

> >>>

> >>> Complex = Complex * Imag + Real;

> >>>

> >>> will change to:

> >>>

> >>> Complex = Real + Imag * Complex;

> >>>

> >>> and now the three commutative functions can be used to process this

> >>> command.

> >>>

> >>> This is far less to write, the intent is clear, fewer functions are

> >>> used

> >>> and I only pay for the programme memory I need.

> >>> This, of course, is not allowed to change the evaluation order of

> >>> operator* and operator+. The operator* will always be evaluated first

> >>> and the operator+ will always work with its result.

> >>> The operator+ is not allowed to steal one of the operator* 's

> >>> parameters.

> >>> commutative will, of course, be available for all functions that take 2

> >>> parameters, not just operators.

> >>>

> >>> These are my thoughts, as already stated above, I would love to hear

> >>> yours.

> >>>

> >>> Sincerely,

> >>> Tobias Wallner

> >>>

> >>> --

> >>> Std-Discussion mailing list

> >>> Std-Discussion_at_[hidden]

> >>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion

> >>>

> >>

> >>

> --

> Std-Discussion mailing list

> Std-Discussion_at_[hidden]

> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion

>

>

> Am 01.09.2020 um 02:51 schrieb Jefferson Carpenter via Std-Discussion:

> > On 8/30/2020 12:35 AM, Jeremy Ong via Std-Discussion wrote:

> >> Perhaps a type trait is a suitable alternative for this (as opposed to

> >> introducing yet another keyword that decorates a function signature).

> >> For

> >> example: https://godbolt.org/z/ecaro9

> >

>

This operator+ has "too perfect forwarding" and can break many other

operators. Here it breaks an ordinary std::string concatenation:

https://godbolt.org/z/bvnd9f

> > +1

> >

> > Also use std::enable_if instead of a static_assert in the function

> > body. This takes advantage of SFINAE so that you can write

> > `does_commute` for some types, `does_anticommute` for other types, etc.

> >

> > https://godbolt.org/z/7ssTjW

> >

>

This isn't quite right. The "template <..., std::enable_if_t<...>>" does

take the template out of overload resolution when the enable_if expression

is false. But when the expression is true, it declares a non-type template

parameter with type void, which is not allowed. The godbolt link doesn't

notice the issue because check_commute now calls the original specific

operator+(complex, float), not the template. One simple fix: Make the type

int instead, and add a default template argument, as in "template <...,

std::enable_if_t<..., int> = 0>". Demo: https://godbolt.org/z/hseceW

I also added std::forward for perfect forwarding. This might help for an

underlying function like X operator+(X x, const Y& y) { x += y; return x; }

> >>

> >> On Sat, Aug 29, 2020 at 6:03 PM Tobias W. via Std-Discussion <

> >> std-discussion_at_[hidden]> wrote:

> >>

> >>> Hi everyone!

> >>> I am coming with a mathematical and embedded systems background and

> >>> there is something that bothered me since I started programming.

> >>> Firstly, I would like to explain the problem with an example that

> >>> occurs

> >>> often in slightly different but similar ways.

> >>> Secondly, I will propose a possible solution.

> >>> Of course, I would love to hear your thoughts.

> >>> So let's imagine we have three classes.

> >>> class Real{

> >>> double value;

> >>> ...

> >>>

> >>> };

> >>>

> >>> class Imag{

> >>> double value;

> >>> ...

> >>>

> >>> }

> >>>

> >>> class Complex{

> >>> double Im;

> >>> double Re;

> >>> ...

> >>>

> >>> };

> >>>

> >>> Then if I was to write functions, for example, an add function or

> >>> operator+ and would like to add them in all possible permutations of

> >>> arguments.

> >>> This means, that I would have to write all those following functions,

> >>> just to add them:

> >>>

> >>> Complex operator+ (Real a, Imag b);

> >>> Complex operator+ (Imag b, Real a); // Mirrored function

> >>> Complex operator+ (Real a, Complex b);

> >>> Complex operator+ ( Complex b, Real a); //Mirrored function

> >>> Complex operator+ (Imag a, Complex b);

> >>> Complex operator+ ( Complex b, Imag a); //Mirrored function

> >>>

> >>> From a mathematical point of view, all mirrored functions are

> >>> obsolete,

> >>> because the intent has already been stated in the function above.

> >>> Furthermore, each mirrored function will use additional program memory

> >>> and this can become an issue on embedded devices.

> >>> Therefore I would like to introduce the idea of the expression

> >>> "commutative" that can be added to functions.

> >>> The commutative expression will tell the compiler that he can switch

> >>> the

> >>> parameters that will be passed to a function.

> >>> Following this, the keyword will only be allowed for functions that

> >>> possess two and only two parameters.

> >>> Then the example from above may look something like this:

> >>>

> >>> commutative Complex operator+ (Real a, Imag b);

> >>> commutative Complex operator+ (Real a, Complex b);

> >>> commutative Complex operator+ (Imag a, Complex b);

> >>>

> >>> If the compiler comes across a statement like below, he is allowed to

> >>> restructure the code.

> >>>

> >>> Complex = Complex * Imag + Real;

> >>>

> >>> will change to:

> >>>

> >>> Complex = Real + Imag * Complex;

> >>>

> >>> and now the three commutative functions can be used to process this

> >>> command.

> >>>

> >>> This is far less to write, the intent is clear, fewer functions are

> >>> used

> >>> and I only pay for the programme memory I need.

> >>> This, of course, is not allowed to change the evaluation order of

> >>> operator* and operator+. The operator* will always be evaluated first

> >>> and the operator+ will always work with its result.

> >>> The operator+ is not allowed to steal one of the operator* 's

> >>> parameters.

> >>> commutative will, of course, be available for all functions that take 2

> >>> parameters, not just operators.

> >>>

> >>> These are my thoughts, as already stated above, I would love to hear

> >>> yours.

> >>>

> >>> Sincerely,

> >>> Tobias Wallner

> >>>

> >>> --

> >>> Std-Discussion mailing list

> >>> Std-Discussion_at_[hidden]

> >>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion

> >>>

> >>

> >>

> --

> Std-Discussion mailing list

> Std-Discussion_at_[hidden]

> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion

>

Received on 2020-09-01 17:11:41