On Fri, Dec 4, 2020 at 11:37 PM Kazutoshi Satoda via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
I saw P0466R5 was adopted, and wonder if it can be safer.

from https://timsong-cpp.github.io/cppwp/n4861/meta.member
> template<class S, class M>
>   constexpr bool is_pointer_interconvertible_with_class(M S::*m) noexcept;
>     Mandates: S is a complete type.
>     Returns: true if and only if S is a standard-layout type, M is an
>       object type, m is not null, and each object s of type S is
>       pointer-interconvertible ([basic.compound]) with its subobject s.*m.
> [ Note: The type of a pointer-to-member expression &C::b is not always a
>   pointer to member of C, leading to potentially surprising results when
>   using these functions in conjunction with inheritance. [ Example:
>     struct A { int a; }; // a standard-layout class
>     struct B { int b; }; // a standard-layout class
>     struct C: public A, public B { }; // not a standard-layout class
>     static_assert( is_pointer_interconvertible_with_class( &C::b ) );
>       // Succeeds because, despite its appearance, &C::b has type
>       // “pointer to member of B of type int”.
>     static_assert( is_pointer_interconvertible_with_class<C>( &C::b ) );
>       // Forces the use of class C, and fails.

So, calling this function without specifying the class to test against
is dangerous.

Sure, but nobody should ever be calling this function — I mean, normal code certainly won't call it. I could imagine one or two calls to it buried way down in the lowest level of some bit-twiddling library. And the name stands out and is greppable just as easily as the similarly dangerous `reinterpret_cast`. The rule for both is similar: "If you use this, (A) you're probably doing it wrong, (B) be careful because there are no guardrails here."

If there's something in this vicinity to improve the safety and teachability of C++, I'd look harder at the idea that &C::b is sometimes not of type (T C::*). That seems like a construct that would come up (handwave) 100x more commonly than `is_pointer_interconvertible_with_class` — which is still far from common, but at least it'd be nice to fix, or at least figure out a specific reason why we can't.

(Even if we could fix the type of &C::b, that's still an extremely uncommon construct, and it might not be worth fixing — just wall up that part of the language and never talk about it again. ;))

my $.02,