The best you can do is collapse all the member accesses into one function. This assumes without checking that everything is a pointer:
template <class C, class PM, class... PMs>
auto access(C* c, PM pm, PMs... pms) {
if constexpr(sizeof...(pms) == 0) {
return c ? std::invoke(pm, c) : nullptr;
} else {
return c ? access(std::invoke(pm, c), pms...) : nullptr;
}
}
Which lets you write:
if (auto r = access(p, &P::q, &Q::r); r) {
r->doSomething();
}
That's ok. Alternatively, you could go a little wild with operator overloading and produce something like:
template <class T>
struct wrap {
wrap(T* t) : t(t) { }
T* t;
template <class PM>
auto operator->*(PM pm) {
return ::wrap{t ? std::invoke(pm, t) : nullptr};
}
explicit operator bool() const { return t; }
T* operator->() { return t; }
};
which lets you write:
if (auto r = wrap{p}->*&P::q->*&Q::r; r) {
r->doSomething();
}
That's also ok. There's unfortunately no ->?
or .?
like operator, so we kind of have to work around the edges.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…