Open ranaanoop opened 3 months ago
So if I understand correctly, one of the problems that this issue deals with is that both int (*ptr_static)(int) = C::g;
and int (*ptr)(int) = C::f;
should be well-formed because both of these uses pointer declarator syntax instead of pointer to member declarator syntax and as per the non-normative note cited in this issue we don't have to use &
before either C::f
as well as C::g
. Meaning these should behave similarly/consistently. But a note is non-normative and normative wording in basic.compound#1.8 puts both static and non-static members to be under pointer-to-member types. So we need to change basic.compound#1.8 to only include non-static data member and implicit object member function so that expr.unary#4 don't apply when forming a pointer to static member function or explicit member function.
Is this correct interpretation of one of the problems raise in this issue?
Is this correct interpretation of one of the problems raise in this issue?
@AlanVoore Yes, exactly.
In addition, this issue also points out that decltype(C::f) func;
is already well-formed as per current wording which is the expected behavior because decltype(C::f) func;
should behave same as decltype(C::g) func;
.
Baiscally, an explicit object member function is supposed to behave like a static member function so they should be consistently handled.
Here is one more demo showing the same problem as discussed in this issue:
struct C
{
static int g(int);
int f(this int);
};
template<typename T> void func(T&);
int main()
{
func(C::g); //accepted by all compiler & well-formed as per current wording
func(C::f); //rejected by gcc and clang but well-formed as per current wording. MSVC accepts this
}
Note func(C::f)
is well-formed as per current wording but rejected by both clang and gcc and accepted by only msvc. Intuitionally, I would expected it to be valid as well. Note (&C::f)(44);
also compiles with gcc and clang and so it works like a static member function as no class type object was needed/passed here in (&C::f)(44);
.
Explicit object member functions cannot be named by a qualified-id unless taking the address or when in a this-transformation context. CWG2902 was amended accordingly. See #573.
Is there any remaining issue here, beyond that?
Full name of submitter: Anoop Rana
Reference (section label): [basic.compound]
Issue description:
I've noticed several issue regarding pointer to member. I'll start by describing one of them here in this issue. This particular issue is about id-expression in [expr.prim.id.general] and the fact that expr.prim.id.general places no restriction on explicit object member function Thus making this program well-formed.
To start with, basic.compound says that:
Note that the highlighted sentence 2 above doesn't make distinction between static and non-static members and it just group all members(static as well as non-static) into the category of/called pointer-to-member type.
Now, we move onto expr.unary.op that states:
This means that
int (*ptr_static)(int) = C::g;
in the below program is ill-formed because we haven't used&
. But practically all compilers accept the program and we usually expect it to work because itg
is a static member function.Note that there is also dcl.mptr that says that a pointer to member shall not point to static member of a class:
The important thing to note here is that this [dcl.mptr#4] and the note above seems to imply that
ptr
is not a pointer to member. Note that this would justify the reason for the working ofC::g
above because we're not forming a pointer to member so expr.unary.op isn't violated. But basic.compound said the pointer to data member and member functions are collectively called pointer-to-member types.So for this first problem I suggest that [basic.compound#1.8.sentence-2] be changed to only include non-static members. Note that basic.compound#1.3 already include static members. So there is one more reason to restrict [basic.compound#1.8.sentence-2] to only include non-static members.
This problem is even more evident/highlighted when considering explicit object member function. For example, consider the following example for which we see implementation divergence:
In this program
#1
is well-formed as per current wording in expr.prim.id.general as explained in this thread but#2
seems to be ill-formed becauseC::f
can't be used to form a pointer to member as&
is not used as per expr.unary.op. Note that msvc accepts both#1
and#2
.Now as per my understanding, the explicit object member function is supposed to behave like a static member function. So I would expect
#2
to work as well even though the current wording makes it ill-formed.So maybe we also need to exempt explicit object member function from basic.compound#1.8.sentence-2.
Basically, ideally
C::f
should not behave like the old pointer to implicit object member function(and instead should behave like a pointerT
) and we don't have to use&
beforeC::f
to get a pointer from it. It should also be able to decay implicitly just like normal functions do. So we might also need to do some modification in [conv.func].Basically, we want to handle these(shown in above code) three cases more consistently.
Suggested resolution:
Change basic.compound#1.8.sentence-2 to only include non-static data members and implicit object member function. Note basic.compound#1.3 already include static members. That is, [basic.compound#1.8] could be changed to as highlighted below:
Note two changes have been made in the above modified reference.
Additionally, basic.compound#1.3 might be modified to include explicit object member function since static members are already included in basic.compound#1.3. That is, [basic.compound#1.3] could be changed to as highlighted below:
These changes will make the shown two code snippets in this issue well-formed.
Sidenote
Bug has been submitted for
decltype(C::f) func;
for gcc.