itemization(
    it() First, the necessary class interfaces are defined. The existence
        of a class tt(Date) is assumed, containing overloaded operators
        like tt(<) and tt(>) to compare dates.
        To start with, we present the interface of the class
        tt(Person), omitting all the standard stuff like overloaded assignment
        operator, (copy) constructors, etc.:
        verb(#include <cstdlib>     // for qsort()

class Date;

class Person
{
    public:
        size_t length() const;
        size_t mass() const;
        char const *name() const;
        char const *city() const;
        Date const &birthdate() const;

    private:
        // all necessary data members
};)

it() Next, the class tt(Person_dbase).
        Within this class a tt(struct CmpPerson) is defined, containing
        two fields:
        itemization(
            it() A pointer to a union of compare functions.

                As the compare functions are static functions of the class
                tt(Person_dbase), pointers to these functions are
                indiscernible from pointers to functions at the global
                (tt(::)) level. The compare functions return tt(int)s (for
                tt(qsort())), and expect two pointers to tt(Person const)
                objects. The field tt(persons) expects the two pointers to
                tt(Person const) objects. The field tt(voids) is the alternate
                interpretation, to be used with tt(qsort()), instead of the
                typecast tt((pif2vp)).

            it() A field tt(pf) (pointer to access function) of
                the nested tt(union Person_accessor).

                The types of as many different access functions of the
                tt(Person) class as are used in the class are declared in this
                union.

                Access functions returning tt(int)s, tt(char const *)s and
                tt(Date &)s are needed. Consequently, the tt(Person_accessor)
                union contains these (three) types.
        )

        From this tt(CmpPerson) struct a static array tt(cmpPerson[]) is
        constructed. It is a tt(static Person_dbase) array, making it possible
        for the compare functions to inspect its elements+footnote( The number
        of elements of the tt(cmpPerson[]) array is not specified in the
        interface: that number is determined at compile-time by the compiler,
        when the static variable tt(cmpPerson[]) is initialized.).

        Also note the tt(static Listtype selector). This variable
        is used by the compare functions to find the actual
        tt(Person) access function to be used.
        Here, then, is the interface of the class tt(Person_dbase):
            verb(class Person_dbase
{
    public:
        enum Listtype
        {
            list_by_length,
            list_by_mass,
            list_by_name,
            list_by_city,
            list_by_birthday,
        };

        // ... constructors etc.

        void list(Listtype type);
                    // list the information
    private:
        struct CmpPerson
        {
            union Compare_function
            {
                int (*persons)// comparing two Persons
                    (Person const *p1, Person const *p2);
                int (*voids)// for qsort()
                    (void const *p1, void const *p2);
            }
                cmp;

            union Person_accessor
            {
                char const
                    *(Person::*cp)() const;
                int
                    (Person::*i)() const;
                Date const
                    &(Person::*d)() const;
            }
                pf;     // to Person's access functions
        };

        static CmpPerson
            cmpPerson[];
        static Listtype
            selector;

        static int cmpstr(Person const *p1,
                          Person const *p2);

        static int cmpint(Person const *p1,
                          Person const *p2);

        static int cmpdate(Person const *p1,
                          Person const *p2);

        Person
            *pp;    // pointer to the info
        size_t
            n;      // number of persons stored.
};)

Next, we define each of the members of the tt(Person_dbase) class
    (as far as necessary).

    it() The tt(list()) function now only has to do three things:
        itemization(
            it() The tt(Listtype) parameter is copied to
                tt(selector),
            it() The function tt(qsort()) is called. Note the
                use of the tt(cmpPerson) array to determine which compare
                function to use.
            it() The information of the tt(Person)objects is
                displayed. This part is left for the reader to implement.
        )
            verb(    void Person_dbase::list(Listtype type)
    {
        selector = type;
        qsort(pp, n, sizeof(Person), cmpPerson[type].cmp.voids);
        // list the sorted Person-database (to be implemented)
    })

it() The array tt(cmpPerson[]) is a static array of tt(CmpPerson)
        elements. In this example there are five different ways to sort
        the data. Consequently, there are five elements in the array
        tt(cmpPerson[]). All these elements can be defined and initialized
        by the compiler. No run-time execution time is needed for this.

        However, note the form of the declaration: the array is defined in
        the scope of the tt(Person_dbase) class. Its elements are
        tt(CmpPerson)s, also defined in the scope of the tt(Person_dbase)
        class. Hence the double mentioning of tt(Person_dbase).
            verb(Person_dbase::CmpPerson
    Person_dbase::cmpPerson[] =
    {
        {       // compare- and access
                // function to compare length
            cmpint,
            Person::length,
        },

        {       // same for mass
            cmpint,
            Person::mass,
        },

        {       // same for name
            cmpstr,
            Person::name,
        },

        {       // same for city
            cmpstr,
            Person::city,
        },

        {       // same for Date
            cmpdate,
            Person::birthdate,
        },
    };)

it() Now only the compare functions remain to be implemented. Although
        five accessors can be used, only three compare functions are needed.

        The compare functions, being static functions, have access to the
        tt(cmpPerson[]) array and to the tt(Listtype selector) variable. This
        information is used by the compare functions to call the relevant
        access member function
        of the two tt(Person) objects, pointed to by the parameters of the
        compare functions.

        For this, the tt(pointer to member) operator
        tt(->*) is used. The element tt(cmpPerson[selector])
        contains the function pointers to the functions to be used:
        they are the fields
        tt(pf), variant tt(cp, i) or tt(d). These fields
        return a pointer to a particular access function of a tt(Person)
        object.

        Through these pointers the functions can be associated to a
        particular tt(Person)
        object using the pointer to member operator. This results in
        expressions like:
        center(tt(p1->*cmpPerson[selector].pf.cp))

        By this time we have
        the name (i.e., address) of an access function for a particular
        tt(Person) object. To call this function, parentheses are needed,
        one set of parentheses to protect this expression from
        desintegrating due to the
        high priority of the second set of parentheses, which are
        needed for the actual call of the function. Hence, we get:
        center(tt((p1->*cmpPerson[selector].pf.cp)()))

        Finally, here are the three compare functions:
            verb(int Person_dbase::cmpstr(Person const *p1, Person const *p2)
{
    return
    (
        strcmp
        (
            (p1->*cmpPerson[selector].pf.cp)(),
            (p2->*cmpPerson[selector].pf.cp)()
        )
    );
}

int Person_dbase::cmpint(Person const *p1, Person const *p2)
{
    return
    (
        (p1->*cmpPerson[selector].pf.i)()
        -
        (p2->*cmpPerson[selector].pf.i)()
    );
}

int Person_dbase::cmpdate(Person const *p1, Person const *p2)
{
    return
    (
        (p1->*cmpPerson[selector].pf.d)()
        <
        (p2->*cmpPerson[selector].pf.d)() ?
            -1
        :
            (p1->*cmpPerson[selector].pf.d)()
            >
            (p2->*cmpPerson[selector].pf.d)()
    );
})

)
