Disclaimer: This is rather more out of curiosity than for a lack of other solutions!
Is it possible to implement a function in C++ that:
- gets passed a pointer of type T
- either returns a reference-like-thing to the object pointed to by T
- or, if the pointer is null, returns a reference-like-thing to a default constructed
T()that has some sane lifetime?
Our first try was:
template<typename T>
T& DefaultIfNullDangling(T* ptr) {
if (!ptr) {
return T(); // xxx warning C4172: returning address of local variable or temporary
} else {
return *ptr;
}
}
A second attempt was done like this:
template<typename T>
T& DefaultIfNull(T* ptr, T&& callSiteTemp = T()) {
if (!ptr) {
return callSiteTemp;
} else {
return *ptr;
}
}
This gets rid of the warning and somewhat extends the lifetime of the temporary, but it's still rather error prone, I think.
Background:
The whole thing was triggered by an access pattern that looked like this:
if (pThing) {
for (auto& subThing : pThing->subs1) {
// ...
if (subThing.pSubSub) {
for (auto& subSubThing : *(subThing.pSubSub)) {
// ...
}
}
}
}
that could be "simplified" to:
for (auto& subThing : DefaultIfNull(pThing).subs1) {
// ...
for (auto& subSubThing : DefaultIfNull(subThing.pSubSub)) {
// ...
}
}
Sadly, but no. There is really no way to fully achieve what you want. Your options are:
constreference, otherwise, you are exposing yourself to a huge can of worms;std::optional<std::ref>and return unset optional if pointer isnullptr. This doesn't really solve your problem, as you still have to check at the call site if theoptionalis set, and you might as well check for the pointer to benullptrinstead at the call site. Alternatively, you can usevalue_orto extract value from optional, which would be akin to next option in a different packaging;