I was reading References, simply and got to the part talking about using optional references. One of the reasons Herb gives to avoid optional<T&>
is because those situations can be "represented about equally well by optional<not_null<T*>>
"
I'm confused about when you would ever want optional<not_null<T*>>
. In my mind, the optional
cancel's out the not_null
, so why wouldn't you just use a raw pointer in a case like this.
CodePudding user response:
For the same reason you might want optional<optional<T>>
.
At some level you code operates with value which might exist or not. Hence optional
.
Value type of that optional value can be T
, not_null<T>
, nullable<T>
or anything else, it does not matter to that code. It just checks for value existence and possibly pass it to some other fucntions.
Those functions represent some other level of code. They can accept their arguments from functions unwrapping optional
, taking address of its member, etc. They have own preconditions: argument should be pointer, and it should not be null. Hence not_null<T*>
.
In the end, you get optional<not_null<T*>>
, because some code expects not_null<T*>
, and other wants to take whatever first want and wrap it in optional
.
CodePudding user response:
It's important to remember the context of the suggestion. The problem that optional<T&>
would solve is cases where a user may or may not have a T
, but if they do, they want you to modify it in some way while still retaining access to it. And that you want to use the optional
interface to handle the "not a value" case.
So if you want to use the optional
interface (and therefore T*
isn't an option), and optional<T&>
is not available by fiat, then you could use optional<T*>
as a substitute. But technically that means that the optional
could have a "value" which is nullptr
. So instead, you use a type that explicitly forbids nullptr
: optional<not_null<T*>>
.
Basically, the suggestion is there to say that you can get the effects of optional<T&>
without the problems that such a type tends to bring.
CodePudding user response:
T*
doesn't have any member functions, whereas optional<not_null<T*>>
has a bunch.
What I'd like is to be able to compose functions like
auto result = maybe_A()
.transform(A_to_B)
.and_then(B_to_opt_C)
.or_else({});
which should be equivalent to
optional<A&> first = maybe_A();
optional<B&> second = first.transform(A_to_B);
optional<C&> third = second.and_then(B_to_opt_C);
C result = third.or_else({});
With pointers, we can't do that as one expression.
A* first = maybe_A();
B* second = first ? A_to_B(*first) : nullptr;
C* third = second ? B_to_opt_C(*second) : nullptr;
C result = third ? *third : {};
Whereas at least with optional<not_null<T*>>
we can adapt our functions
optional<not_null<A*>> first = maybe_A();
optional<not_null<B*>> second = first.transform([](not_null<A*> a){ return &A_to_B(*a); });
optional<not_null<C*>> third = second.and_then([](not_null<B*> b){ return B_to_opt_C(*b); });
C result = third.or_else({});
a.k.a
auto result = maybe_A()
.transform([](not_null<A*> a){ return &A_to_B(*a); })
.and_then([](not_null<B*> b){ return B_to_opt_C(*b); })
.or_else({});