2 ms·
> If you want an optional reference to something, maybe you don't entirely understand references. A reference isn't optional; it has to refer to something. I'm
by kllrnohj 5y ago
> If you want an optional reference to something, maybe you don't entirely understand references. A reference isn't optional; it has to refer to something.
I'm not sure how you wrote this but then didn't immediately realize why optional<T&> would be useful.
> std::optional is a container: it contains a value, which may be indicated as not being present. A reference isn't a value which is contained; it's a value which is somewhere else. If you contain a reference, the reference must be resolved to a valid object.
And yet std::reference_wrapper exists and basically ruins your entire thesis. There's no conceptual problem with storing references in containers; `struct Foo { int& i; }` is exactly that and has worked since forever. Rather it's a problem with the implementation of optional<> specifically that prevents it. And why reference_wrapper exists, to "fix" those implementation issues - primarily with types that already existed like vector, which is why it's silly it's still needed on new types like optional.
- kazinator 5y agoThe key is to avoid equivocating between "C++ reference" and "some kind of value that indicates another value elsewhere". C++ references cannot be optional by design; that is one of the aspects of pointers that C++ references "fix", and you cannot code around it. A key idea behind references is to get rid of the null-based optionality of pointers (nowadays referrred to as the "billion dollar mistake"). The author of the article would like to use the declaration syntax of references T& in the middle of some templateology to produce an optional reference; but that optional reference itself cannot have anything to do with C++ references. If the abstraction doesn't actually have C++ reference semantics in it, why would you want to specify any aspect of it using C++ reference syntax? Because it is poetically memetic or something? reference_wrapper doesn't actually have anything to do with references; it doesn't have to be used with references and isn't implemented literally as a wrapper around a reference: implementations contain a pointer. It really should lose the _wrapper from its name, which provides no information about it. Where is the reference here? #include <iostream> #include <utility> #include <functional> using std::reference_wrapper; using std::cout, std::endl; using std::swap; int main() { int x = 42, y = 73; reference_wrapper rx(x); reference_wrapper ry(y); swap(rx, ry); // swap pointers cout << rx << ", " << ry << endl; // 73, 42 cout << x << ", " << y << endl; // 42, 73: stayed where they are } It looks pretty much like a rudimentary smart pointer.
- kllrnohj 5y ago> C++ references cannot be optional by design; that is one of the aspects of pointers that C++ references "fix", and you cannot code around it. You keep repeating this as if it's at all relevant. The single purpose of std::optional is to make things optional that cannot themselves be optional by design. That C++ references cannot be optional are exactly why it's a perfect fit for std::optional. You seem to be talking about the difficulty in storing T& if the value isn't present. That's not actually hard to do, that's what std::reference_wrapper does already. The C++ standard library already solved that, and trivially so. Rather the issue is a difference in assignment behavior, as the Boost.Optional discusses: https://www.boost.org/doc/libs/1_69_0/libs/optional/doc/html/boost_optional/rebinding_semantics_for_assignment_of_optional_references.html https://www.boost.org/doc/libs/1_69_0/libs/optional/doc/html... (and Boost.Optional does allow T&, because optional<T&> is well-formed & well-defined) > reference_wrapper doesn't actually have anything to do with references What? Literally from the documentation: "std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references." The only thing it does is take a T& and return a T&. That it stores it internally as a T* is an implementation detail. As for your example snippet, you just have a bug in usage since you didn't read reference_wrappers docs. It needs to be `swap(rx.get(), ry.get());` since the _wrapper part of its name is actually significant, you have to get the wrapped value out of it. Alternatively `swap((int&) rx, (int&) ry);` would also have worked.