Proposal: a "Components" template with partial specializations implicitly defined for typical classes

47 views
Skip to first unread message

W Karas

unread,
Mar 16, 2016, 2:10:13 AM3/16/16
to

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...@vandevoorde.com ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

Reply all
Reply to author
Forward
0 new messages