I have a class Widget with some private internals, but I would like to expose these internals to predicate functors (only) via friendship.
class Widget
{
ComponentA a;
ComponentB b;
friend class WidgetPredicate;
};
class WidgetPredicate : public std::unary_function<bool, const Widget&>
{
bool operator () (const Widget& w) const
{
// inspect a and b and make a yes/no decision
}
};
The intent is that I can use the WidgetPredicate function as a sifter in all the std::xxxx_if family of algorithms.
However, I would like to leave some extensibility in the system where a future developer could make new predicates that somehow inheirit the friend status neatly. Is there a good design idiom for this? My current (non) solution is that everything in Widget is public.
I tried toying around with a base class that exposed the internals of Widget to subtypes of WidgetPredicate through protected functions, something like:
class WidgetPredicate : public std::unary ...
{
protected:
const ComponentA& expose_a ( const Widget& w ) const { return w.a; }
const ComponentB& expose_b ( const Widget& w ) const { return w.b; }
public:
virtual bool operator () ...
};
class DerivedWidgetPredicate : public WidgetPredicate
{
public:
virtual bool operator () (const Widget& w)
{
const ComponentA& a = this->expose_a(w); // a can now be inspected/predicated upon
const ComponentB& b = this->expose_b(w); // b ...
}
};
I can live with the potential that now any class could examine Widget's internals just by saying :public WidgetPredicate. I am not trying to protect against malicious developers, so if they say they're a friendly WidgetPredicate then I am willing to take that at face value. The syntax is also subpar, but I can live with that too. What I don't like the maintainence issue, that when I change the internals of Widget I have to also add new expose() methods to the base predicate. (IMO That process could and should be mechanical).
I could always put the expose methods directly in the Widget class, but IMO at that point I might as well make the fields public and just live with it (ie my current soln).