# . , , if foo null, null, foo null, foo->bar.
++.
return (foo) ? (foo->bar) ? foo->bar->baz : nullptr : nullptr;
, , , .
#define Maybe(X, Y) (X)?X->Y:nullptr
return Maybe(foo, Maybe(foo->bar, baz));
, , , , , .
, " ", Mooing Duck .
template<typename T_Return, typename T_X, T_Return* T_X::*Y>
T_Return* Maybe(T_X* pX)
{
return (pX) ? pX->*Y : nullptr;
}
return Maybe<Baz, Bar, &Bar::baz>(Maybe<Bar, Foo, &Foo::bar(foo));
, , .
, , , Null Propagation, , , "" . :
// C
if(foo != null) { foo.Bar(); }
# :
foo?.Bar()
, "" .
#define Maybe(X) if (auto tempX = (X)) tempX
Maybe(GetFoo())->Bar();
Maybe(GetFoo()->bar = new Bar();
, ?: inline if.
, .
, - :
if (tempX != nullptr) \
{ \
return tempX->Y; \
} \
else \
{ \
return nullptr; \
} \
:
#define ReturnMaybe(X, Y) auto tempX = X; if(tempX) { return tempX->Y; }else{return nullptr;}
Bar* GetBar()
{
ReturnMaybe(GetFoo(), bar)
}
(, , ), - .
Change Made the template answer a little better.
Edit 2 - talked about this with colleagues and came up with some other options:
#define Maybe(X) (X==nullptr) ? nullptr : X
Using:
return Maybe(foo)->bar;
Interestingly, this also works in case of a call.
Maybe(foo)->Bar();
because what it expands is indeed (albeit strange)
(foo == nullptr)? nullptr: foo-> Bar ();
However, since you cannot put a variable declaration in ?: shorthand, you cannot protect against
return Maybe(get_next_parent())->child;
as described in Mooing Duck, and you will need to create a temporary place.