Home > Enterprise >  Msvc compiles &(Class::mem) but gcc does not
Msvc compiles &(Class::mem) but gcc does not

Time:11-05

I have recently learnt about pointer to member syntax and then wrote the program shown below that msvc compiles but gcc and clang rejects.

#include <iostream>
#include <type_traits> 
#include <concepts>
struct C
{
    int foo()
    {
    return 5;
    }
};
int main()
{ 
      int (C::*ptr)() = &(C::foo);   //msvc compiles but not gcc and clang  
}  

I want to know which one is correct. Live demo

CodePudding user response:

The code is ill-formed, MSVC is wrong.

[expr.unary.op]/3

If the operand is a qualified-id naming a non-static or variant member m of some class C, other than an explicit object member function, the result has type “pointer to member of class C of type T” and designates C::​m.

Otherwise, the result has type “pointer to T” ...

In &(C::foo), (C::foo) is not a qualified-id (C::foo would be one), but rather a primary-expression.

Also [expr.unary.op]/4 is even more explicit:

A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses.

The rationale behind this is to have a syntax for forming a regular (non-member) pointer, in case you need one (as opposed to a member-pointer):

#include <type_traits>

struct A
{
    int x;
};

struct B : A
{
    int x;

    void foo()
    {
        auto f = &A::x;
        static_assert(std::is_same_v<decltype(f), int A::*>);

        auto g = &(A::x);
        static_assert(std::is_same_v<decltype(g), int *>);
    }
};

MSVC also accepts this code, so I guess they're only being non-conformant for member functions, not data members (which isn't a big deal, since for member functions &(C::foo) is otherwise always illegal).

CodePudding user response:

This is P2904 which proposes that the program be well-formed.

Note again that as per the current wording the program is ill-formed but the above paper proposes to make it well-formed by removing the exception in the normal precedence rules. Here is the relevant change in the wording as proposed by the paper:

Change in wording

Change [expr.unary.op#4] to as shown below:

A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses.

[Note 4: That is, the expression &(qualified-id), where the qualified-id is enclosed in parentheses, does not form an expression of type pointer to member . Neither does. The expression qualified-id does not form an expression of type pointer to member, be- cause there is no implicit conversion from a qualified-id for a non-static member function to the type “pointer to member function” as there is from an lvalue of function type to the type “pointer to function” ([conv.func]). Nor Neither is &unqualified-id a pointer to member, even within the scope of the unqualified-id’s class. — end note]

  • Related