• Proposal: a "Components" template with partial specializations implicit

    From W Karas@21:1/5 to All on Wed Mar 16 01:05:44 2016
    A "primitive" template named "Components" with this interface:
    <pre>
    template <
    class Target,
    template <typename Member_type, Member_type Target::*mptr>
    class Op,
    typename Param>
    struct Components
    {
    bool operator () (Param & param);
    };
    </pre>
    The Op parameter is presumed to fulfill the constraint:
    <pre>
    Param & param;
    Op<Member_type, &Target::member> op;
    bool b = op(param);
    </pre>
    for all data members and base classes of the class Target. The
    function operator of Components would be generated implicitly. It
    would instantiate Op for each component of Target, create an instance
    of the instantiated class, and call its function operator as shown in
    the constraint above, forwarding to it the parameter 'param'. If the
    call returned false, the function operator of Components would return
    false immediately. If all the calls for components returned true, the Components operator would also return true.

    For example, for this class:
    <pre>
    struct A { int i, j; double x; };
    </pre>
    the compiler would implicitly generate the equivalent of the following
    partial specialization of Components:
    <pre>
    template <
    template <typename Member_type, Member_type A::*mptr> class Op,
    typename Param>
    struct Components<A, Op, Param>
    {
    bool operator () (Param & param)
    {
    return(
    Op<int, &A::i>()(param) &&
    Op<int, &A::j>()(param) &&
    Op<double, &A::x>()(param));
    }
    };
    </pre>
    This would make it possible to define a default operator == as a
    library template:
    <pre>
    template <class Target>
    class Equality_op;

    template <class Target>
    class Equality_param
    {
    friend class Equality_op<Target>;

    const Target &op1, &op2;

    public:
    Equality_param(const Target &op1_, const Target &op2_)
    : op1(op1_), op2(op2_) { }
    };

    template <class Target>
    struct Equality_op
    {
    template <typename Member_type, Member_type Target::*mptr>
    struct Op
    {
    bool operator () (Equality_param<Target> & param)
    {
    return(param.op1.*mptr == param.op2.*mptr);
    }
    };
    };

    template <class Target>
    bool operator == (const Target &op1, const Target &op2)
    {
    Equality_param<Target> param(op1, op2);

    Components<
    Target, Equality_op<Target>::template Op, Equality_param<Target> > c;

    return(c(param));
    }
    </pre>
    Likewise for default operators > and <.

    This implies that member pointers can point to base classes, which I'm
    guessing is an idea that's been rejected before. So doing this would
    create "pressure" to accept the syntax:
    <pre>
    Base Derived::*p = &Derived::Base;
    </pre>
    There would also be a need for another "primitive" template Components_no_virt_base that would skip over virtual base classes I
    think.

    A nice thing about this approach is that the default == operator could sometimes be "fixed" rather than discarded. For example, suppose the
    default == operator worked for a class "Big" except for one data
    member "argh", which was a pointer to a heap object. One could handle
    this with an overriding instantiation of "Equality_op":
    <pre>
    template <>
    struct Equality_op<Big>
    {
    template <>
    struct Op<Argh, &Big::argh>
    {
    bool operator () (Equality_param<Target> & param)
    {
    // ...
    }
    };
    };
    </pre>



    --
    [ comp.std.c++ is moderated. To submit articles, try posting with your ]
    [ newsreader. If that fails, use mailto:std-cpp-submit@vandevoorde.com ]
    [ --- Please see the FAQ before posting. --- ]
    [ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)