ISO: WG21/N0496 ANSI: 93-0109 Author: John Max Skaller Date: 9/1/94 Reply to: maxtal@suphys.physics.su.oz.au "COMPLETING POINTER TO MEMBER FUNCTIONALITY" ------------------------------------------ Pointers to members exist principally to enable late binding of the object pointer, as a type-safe alternative to use of casts and the offsetof macro. Such a system must be functionally complete to be of more than limited use. Such a system must be notationally complete and symmetrical to be of use in templates. Unfortunately, they aren't. Consider the following: struct Inner { Mem mem; }; Mem Inner::*ptmem = &Inner::mem; struct Outer { Inner inner; }; Inner Outer::*ptminner = &Outer::inner; Outer outer; Outer *pouter = &outer; PROPOSAL 1: Forming pointers to members --------------------------------------- If a class type Outer contains an member inner of class type Inner and Inner contains a member mem of type Mem, then Mem may be considered as a member of Outer and a pointer to member can be obtained with the notation: Mem Outer::ptoim* = &Outer::inner.mem; Comment: this operation is required for functional completeness of pointers to members. PROPOSAL 2: Adding pointers to member together ---------------------------------------------- If a class type Outer contains a member inner of class type Inner, and Inner contains a member mem of type Mem, then a pointer to member ptm of type Mem Inner::* may be added to a pointer to member ptminner of type Inner Outer::* to obtain a pointer to member of type Mem Outer::* such that ptminner .* ptmem == &Outer::inner.mem; Comment: this operation is required for functional completeness of pointers to members. PROPOSAL 3: Adding a member to a pointer to member -------------------------------------------------- If a class type Outer contains a member inner of class type Inner, and Inner contains a member mem of type Mem, then the member mem may be added to a pointer to member ptminner of type Inner Outer::* to obtain a pointer to member of type Mem Outer::* such that ptminner . mem == &Outer::inner.mem; Comment: this operation can be defined by ptminner . mem == ptminner .* (&Inner::mem) which utilises the new operation defined in proposal 2, provided the class of which mem is a member is known to be Inner. PROPOSAL 4: Conveniences ------------------------ The following two overloads are added for convenience pouter . inner == &(pouter->inner) pouter .* ptminner == &(pouter->*ptminner) Neither are essential either for functional completeness or referential completeness, however the use of infix notation is vastly superior to the clumbsy form of the RHS when several levels of containment or indirection are involved: pa . b . c . d == (&(&(pa->b)->c)->d ------------------------------------------------------------ Comments: ALL the operations involved in this proposal simply add the RHS offset to the LHS, yielding an exprsssion of the same category (lvalue, pointer, pointer to member) as the LHS, but indicating the member contained at the nominated offset. I call this an 'incast', the operation is always safe and corresponds to the notion that a nested (or inner) member, which is a member of a member, is also in some sense a member of the outer structure. Incasting consists of adding an offset to an address with appropriate type changes. The inverse of this operation, which I call an 'outcast', is unsafe but extremely useful, it corresponds to the idea that we can find the address of an object if we know the address of a contained object and which member of the containing object it is: the operation is simply a subtraction with appropriate type changes.