C++ Logo


Advanced search

Re: P0466: about the danger of type parameters deduced by &C::m

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Sat, 5 Dec 2020 09:59:39 -0500
On Fri, Dec 4, 2020 at 11:37 PM Kazutoshi Satoda via Std-Proposals <
std-proposals_at_[hidden]> 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,

Received on 2020-12-05 08:59:51