Date: Wed, 2 Sep 2020 22:38:19 +0200
Hi, all
First of all, I am glad that so many are taking part in this discussion.
I was wondering if we really need to declare the typetrait commutative
between two types.
Maybe the trait of being commutative should only be part of one type in
itself.
And if it is commutiative it will be part of the whole "commutative family".
I tried it and it also seems to fix the problem with the strings.
https://godbolt.org/z/n3cPTz
have a look :)
BR,
Tobias
Am 02.09.2020 um 00:07 schrieb Andrew Schepler:
>
>
> 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]
> <mailto: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]
> <mailto:Std-Discussion_at_[hidden]>
> >>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
> >>>
> >>
> >>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> <mailto:Std-Discussion_at_[hidden]>
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
First of all, I am glad that so many are taking part in this discussion.
I was wondering if we really need to declare the typetrait commutative
between two types.
Maybe the trait of being commutative should only be part of one type in
itself.
And if it is commutiative it will be part of the whole "commutative family".
I tried it and it also seems to fix the problem with the strings.
https://godbolt.org/z/n3cPTz
have a look :)
BR,
Tobias
Am 02.09.2020 um 00:07 schrieb Andrew Schepler:
>
>
> 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]
> <mailto: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]
> <mailto:Std-Discussion_at_[hidden]>
> >>> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
> >>>
> >>
> >>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> <mailto:Std-Discussion_at_[hidden]>
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion
>
Received on 2020-09-02 15:41:55