Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[expr.mptr.oper] Clarify pointer-to-member operators. #4733

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jensmaurer
Copy link
Member

Fixes #4703

@@ -5795,7 +5794,10 @@
The restrictions on cv-qualification, and the manner in which
the cv-qualifiers of the operands are combined to produce the
cv-qualifiers of the result, are the same as the rules for
\tcode{E1.E2} given in~\ref{expr.ref}.
\tcode{E1.EM} given in~\ref{expr.ref},
Copy link
Contributor

@xmh0511 xmh0511 Jul 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jensmaurer Maybe, we should say that

EM is a qualified-id T::m naming a member m of class T declared with type X where the member is pointed by the value of the second operand, ignoring mutable specifier(if any).

In order to make the name lookup rule can uniformed work here; for instance, in a derived class, there is a member with the name m hides the member of the same name declared in the base class. The purpose of this utterance prevents the lookup rule from recklessly starting to perform in the scope associated with the object expression.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think name lookup considerations are not really relevant here. I say "EM must name a member of T" below; plus EM has a unique name (it's hypothetical / invented), so there is no hiding in view.
All that's relevant is the type of EM and the fact it's non-static and non-mutable; everything else falls out of the expr.ref rules.

Copy link
Contributor

@xmh0511 xmh0511 Jul 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect that the expression E1.EM can additionally state what the result is, after all, [expr.mptr.oper#2] merely says "The result is an object or a function of the type X", but it didn't specify which object or function is it, which needs the help of the relevant rule about the result of E1.EM cited below. Except for that, the original utterance is ok for stating type.

If E2 is a non-static data member..., the expression designates the corresponding member subobject of the object designated by the first expression.

The type of E1.E2 is the type of E2 and E1.E2 refers to the function referred to by E2.

Copy link
Contributor

@xmh0511 xmh0511 Jul 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I think the paragraph [expr.mptr.oper#5] should be changed to that

The result of E1.*E2 is determined by E1.EM([expr.ref]), where EM is a qualified-id T::m naming a member m of class T to which the value of E2 refers and the mutable specifier in the declaration of the member is ignored(if any). Except that If the value of E2 refers to a non-static member function that is virtual([class.virtual]), the function designated by E1.*E2 is the final overrider in the dynamic type of the object expression(i.e, the type of the result remains determined by E1.EM).

Now, the [expr.mptr.oper#5] specifies all the respects regard the result of expression E1.*E2(e.g, which object or function does the result denote).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we just say "E2 points to" instead of "the value of E2 points to"? It's a pointer, it points to things.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E2 is an expression, so it presumably it has a value.

That said, I note that @xmh0511 also laments the absence of a specification what the result value actually is, so some massaging to the original wording is probably necessary. I would like to avoid talking in "identifiers" for anything but finding out the cv-qualification of the result type, if we can help it. There's too much name lookup / virtual function etc baggage around "identifier".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to use "the value of E2" to avoid a similar issue mentioned in #4662 (comment). But, it seems you're right that the meaning is unambiguous if using "E2 points to". However, the benefit of using "the value of ..." is that it implies the lvalue-to-rvalue conversion shall be applied to the operand(if necessary), which is also under-specified in many sections in [expr].

Copy link
Contributor

@xmh0511 xmh0511 Jul 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jensmaurer Not strictly, a pointer to member records the information of the entity and its class, hence I think that we use T::m is equivalent to use the entity pointed to by the pointer to member in most respects. The exception is the virtual function, which has been listed in the proposed wording. IMHO, the wording could probably cover all cases.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider the second operand may result from Pointer-to-member conversions, I think we should separate [expr.mptr.oper#2] into two parts; One part phrases type of the result, the other phrases the entity of the result. Since the wording about the type of the result in the current changed file is ok, we should pay attention to the entity designated by the result.

The entity designated by E1.*E2 is determined by E1.EM([expr.ref]), where EM is a qualified-id T::m naming the member to which the value of E2 refers, except that If the value of E2 refers to a virtual function, the function designated by E1.*E2 is the final overrider in the dynamic type of the object expression.

Since the relevant rule defined in [conv.mem]

The result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to the member in D's instance of B.

So, even if the operand E2 is taken from the result of Pointer-to-member conversions, its value still refers to the original member, which is the entity that E1.*E2 designates.

@tkoeppe
Copy link
Contributor

tkoeppe commented Mar 13, 2023

@jensmaurer Any thoughts on this proposal? Would you like any other input?

@jensmaurer jensmaurer added the cwg Issue must be reviewed by CWG. label Mar 13, 2023
@jensmaurer
Copy link
Member Author

@tkoeppe, I think I want CWG review for this eventually.

@wg21bot wg21bot added the needs rebase The pull request needs a git rebase to resolve merge conflicts. label Jul 22, 2023
@tkoeppe
Copy link
Contributor

tkoeppe commented Nov 12, 2023

Could you please rebase?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cwg Issue must be reviewed by CWG. needs rebase The pull request needs a git rebase to resolve merge conflicts.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Mislead utterance of section [expr.mptr.oper]
5 participants