The non-static member functions which we have now do not accept the 'implicit object argument' by value. It has to be passed by reference. If the proposal will simply introduce a new syntax to define that kind of functions, then the proposed syntax shouldn't allow the object parameter to be non-reference. If you do that, you should not run into any kind of problems with regard to the type of the function pointer.

Complexity is inevitable. What should be avoided is needless complexity.

Of course, people can disagree over what is needless and what is needed.



From: Std-Discussion <std-discussion-bounces@lists.isocpp.org> on behalf of Jason McKesson via Std-Discussion <std-discussion@lists.isocpp.org>
Sent: Monday, August 2, 2021 4:45 PM
To: std-discussion@lists.isocpp.org <std-discussion@lists.isocpp.org>
Cc: Jason McKesson <jmckesson@gmail.com>
Subject: Re: [std-discussion] Fw: The unnecessary confusion of the C++23 proposal P0847R6
 
On Mon, Aug 2, 2021 at 4:19 PM Hani Deek via Std-Discussion
<std-discussion@lists.isocpp.org> wrote:
>
> > I'm sorry, but I fail to connect your response with Jason's comments.
> > This technical discussion would benefit from some specifics from you
>
> OK, I will try to give some quick responses per your request.
>
> > Let's say we do what you say. We define that these functions are
> >  non-static in every way. So... what is the type of this:
>
> >  ```
> >  struct foo
> >  {
> >   void ex_mem(this foo self);
> >  };
> >  ```
>
> > That is, what is the type of `&foo::ex_mem`?
>
> > If this function must in all ways be a regular non-static member
> > function, then that `self` parameter needs to go away. After all,
> > member pointer syntax is of the form
> > `ReturnType(ClassName::*)(Parameters) Qualifiers`. The implicit `this`
> > parameter is defined by the `Qualifiers`, not the `Parameters`.
>
> > So now a user needs to stick the first parameter in the `Qualifiers`
> > section. Personally, I would find this to be *incredibly* confusing.
> > The parameters of a function declaration should match the parameters
> > in a member pointer. You shouldn't have to shuffle them around for no
> > reason.
>
> > Note that the current proposed behavior doesn't have this problem. The
> > parameters in the declaration are always the same when used as a
> > function pointer.
>
> You say that the form of the static function pointer syntax matches better the form of the proposed function declaration syntax, and for that reason you (presumably) think that the proposed function declaration syntax should be assigned to a new kind of member functions as proposed in the paper.

This is not a good representation of my point.

My point is that what you get out of `&foo::ex_mem` has to be
*something*. You have 3 choices: a pointer-to-member-function, a
function pointer, or some new, third thing. You don't like new, third
things; that's what this thread is about after all. So it's either a
pointer-to-member-function or a function pointer.

Having it be a pointer-to-member-function creates a number of
complexities regarding the relationship between the declaration and
the type of the pointer-to-member-function. Making it work would
require adding some new syntax to the language, and possibly a keyword
or two.

By contrast, having it be a function pointer creates no such
complexities; the signature of the declaration is the signature of the
pointer. Therefore, we should take the simplest, clearest, most
obvious solution: return a function pointer.

But think about what this *means* for `foo::ex_mem`. One of the big
differences between a static member and a non-static member is what
`&type::member` resolves to. Static members resolve to an
object/function pointer, while non-static members resolve to a
completely different construct. This is a key difference between the
two groups of functions.

So what is `foo::ex_mem`? It's a non-static member function... but not
when you get the address of it. Or it is a static member function...
but not when you call it with `obj->ex_mem()` notation. So which is
it?

Well, it's clearly a thing that has certain traits of both but isn't
entirely either. For the most part, you can treat it like a non-static
member. But in some cases, it acts like a static member.

Put another way, you're going to get complexity *somewhere*. Either
you're going to have a complicated way of figuring out what the member
pointer type is from one of these functions, or you're going to
complicate the binary static/non-static classification of member
functions. Why is complexity in the former domain preferred to the
latter?

> <snip>
> > You keep saying that it is "complexity" but you never explain *why*
> > this is "complexity". Consider the above: I went into detail as to
> > exactly where your proposal would add complexity.
>
> The complexity I am referring to relates to concepts defined in the standard, not to the shape of the code.
> Currently we have two kinds of member functions defined in the standard. If you add one more hybrid type, then you have made the overall conceptual framework more complex.

OK, let's go with that.

I do not believe that complexity, in and of itself, is not a problem.
Complexity is only a problem when it is a *problem*. When it makes
something difficult to understand or work with. When it has a bunch of
gotchas that require you to constantly re-think how you can work with
the tool. When it makes a programmer's life using the language
actively worse.

Adding `enum class` in C++11 as an alternative kind of enumeration
added "complexity", as these new enumerations have specialized rules
around them. But it didn't make the language harder to work with.

Adding `concept` and `requires` as language forms of SFINAE techniques
like `std::enable_if` added "complexity" and *lots* of it. It's a new
kind of language construct, with a thousand and one rules built around
it. There are concept subsumption rules, rules about what counts as
"more constrained" which basically acts as its own form of function
overloading rules. But they didn't make the language harder to work
with. If anything, it got *easier* to do more complicated things.

So allow me to rephrase my question: what will users actually have a
problem doing with this code? Will a programmer's life using the
language be made measurably worse, and if so, how?

> Like I said in the previous message, the basic problem underlying your argumentation is your belief that we should ignore the standard and its concepts because those things do not concern the average C++ user. Your argumentation is focused entirely on the shape of the code and makes no reference what so ever to the concepts that people learn from the text of the standard.

Because at the end of the day, "the shape of the code" is *all* that matters.

Pretty much every feature added to C++ technically increases its
complexity. The question is whether that increase is worth the
benefits. And the way that gets measured is in "the shape of the
code".

And yes, the shape of the standard does not concern the average C++
user all that much. The average C++ user doesn't learn the language
from the standard (and probably shouldn't). The average C++ user picks
up new features from tutorials, presentations, or other similar
materials as their compilers-of-interest implement them.

And this is true of most languages. For languages that have a standard
document at all, most users of that language have not read it.

The complexity of a standard is not unimportant. But we shouldn't make
decisions as if textual complexity has a major effect on the daily
life of most programmers. As if most programmers bemoaned C++ because
of its lengthy standardese, rather than the difficulty of the language
that standard defines.