On Sun, 1 Aug 2021 at 21:15, Andrey Semashev via Std-Proposals <std-proposals@lists.isocpp.org> wrote:
On 8/1/21 10:52 PM, Barry Revzin via Std-Proposals wrote:
>
>
> On Sun, Aug 1, 2021 at 2:41 AM Fabio Alemagna <falemagn@gmail.com
> <mailto:falemagn@gmail.com>> wrote:
>
>
>
>     Il giorno gio 29 lug 2021 alle ore 02:30 Barry Revzin via
>     Std-Proposals <std-proposals@lists.isocpp.org
>     <mailto:std-proposals@lists.isocpp.org>> ha scritto:
>
>
>         What would you do if value_at returned a T*? You can't do
>         value_or() on a T*, because pointers have very few operations
>         you can do on them (and nearly all of those would be straight up
>         invalid in this use-case - which does not make for a great API!)
>         you'd either push for some language feature that does that or
>         you'd write some non-member function that handles this case.
>         Which would be fine for value_or(), but not for any number of
>         other operations that work for optional but not for pointers.
>         What if you wanted the size of the span there, or 0?
>
>         With optional, these things just compose straightforwardly, so:
>         m.value_at(p).transform(ranges::size).value_or(0)
>
>         How do you do that with a pointer?
>
>         Note that neither of these examples work with
>         optional<reference_wrapper<T>> either.
>
>
>     It seems to me you do need a pointer, because they carry an
>     intrinsic "optionality" semantics with themselves, yet bare pointers
>     lack the functionalities std::optional has, such as the value_or()
>     method and possibly others. As already stated one can't have
>     std::optional<T&> and std::optional<std::reference_wrapper<T>> is a
>     substitute of it.
>
>     But I believe we can have the best of both worlds: we could wrap a
>     pointer into a special type that std::optional would be specialized
>     over, so that you can actually do things like
>
>          m.value_at(p).value_or(...);
>
>     As in the below example:
>
>     int main() {
>          test_class test("hello");
>
>          std::cout << test.value_at("hello").value_or("not found") <<
>     std::endl;
>          std::cout << test.value_at("unexisting").value_or("not found")
>     << std::endl;
>
>          return 0;
>     }
>
>     Which would produce this output:
>
>          hello
>          not found
>
>     I've built a working example on godbolt. Have a look:
>     https://godbolt.org/z/6K7ahb3v4 <https://godbolt.org/z/6K7ahb3v4>
>
>     Regards,
>     Fabio
>
>
> The reason optional<T&> is a vastly superior solution to
> optional<reference_wrapper<T>> is because:
>
> 1) Given a U, you want to be able to write optional<U>. The former lets
> you do that, and the latter requires you to write
> optional<some_metafunction<U>> - which is very tedious for producers.
> 2) optional<T&> holds a T&, but optional<reference_wrapper<T>> holds a
> reference_wrapper<T> - those have very different API surfaces, the
> former being much easier to use - unless you do more metaprogramming -
> which is very tedious for consumers.

3) optional<T&> can be optimized to store T* inside while
optional<reference_wrapper<T>> cannot.

Well, given that the same library provides both, actually it can - you'd just need to make optional<reference_wrapper<T>> a friend of reference_wrapper<T> so that it can put the latter into a hidden singular state.