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.
"With a little Boilerplate..."
We can get to this:
p >> q >> r >> doSomething();
Here's the boilerplate...
#include <iostream>
struct R {
void doSomething()
{
std::cout << "something\n";
}
};
struct Q {
R* r;
};
struct P {
Q* q;
};
struct get_r {};
constexpr auto r = get_r{};
struct get_q {};
constexpr auto q = get_q{};
struct do_something {
constexpr auto operator()() const {
return *this;
}
};
constexpr auto doSomething = do_something {};
auto operator >> (P* p, get_q) -> Q* {
if (p) return p->q;
else return nullptr;
}
auto operator >> (Q* q, get_r) -> R* {
if (q) return q->r;
else return nullptr;
}
auto operator >> (R* r, do_something)
{
if (r) r->doSomething();
}
void foo(P* p)
{
//if (p && p->q && p->q->r)
// p->q->r->DoSomething();
p >> q >> r >> doSomething();
}
The resulting assembly is very acceptable. The journey to this point may not be...
foo(P*):
test rdi, rdi
je .L21
mov rax, QWORD PTR [rdi]
test rax, rax
je .L21
cmp QWORD PTR [rax], 0
je .L21
mov edx, 10
mov esi, OFFSET FLAT:.LC0
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
.L21:
ret
Videos
Let's walk through this logically.
var f = ???;
var i = f?.Measure;
var t = i.HasValue;
We don't know if f is null or not.
- If
fis null, then the result (i) isnull - If
fis not null, then the result (i) is anint
Therefore, i is defined as int?, and t is a bool
Now, let's walk through this:
var f = ???;
var i = f?.Measure.HasValue;
- If
fis null, then the result (i) is null - If
fis not null, then the result (i) isMeasure.HasValue, which is a bool.
Therefore, i is a bool?.
If f is null, we short-circuit and return null. If it's not, we return the bool result of .HasValue.
Essentially, when using ?. - the return type must be a reference value, or a Nullable<T>, as the expression can short circuit to return null.
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null
In this case, f is null.
The reason why i.HasValue returned false is because i is of type Nullable<int>. So even when the value of i is null, like in this case, i.HasValue is still accessible.
However, f?.Measure.HasValue immediately returns null after f? is evaluated. Hence the result you see above.
Just to quote Rob's comment:
The main thing to realise is that you're reading and understanding this: f?.Measure.HasValue as this: (f?.Measure).HasValue, which it's not.
Is there something like a Safe Navigation Operator that can be used on Arrays?
Yes, what you are looking for is known as the Optional Chaining operator (JavaScript / TypeScript).
The syntax shown in the MDN JavaScript documentation is:
obj.val?.prop
obj.val?.[expr]
obj.arr?.[index]
obj.func?.(args)
So, to achieve what you want, you need to change your example from:
<h6>{{simpleData?[0]}}</h6>
To:
<h6>{{simpleData?.[0]}}</h6>
^
Also see How to use optional chaining with array in Typescript?.
is there a more simpler(by code) way just like the Safe Navigation Operator?
There is ternary operator.
condition ? expr1 : expr2
<h6>{{simpleData?simpleData[0]:''}}</h6>