3 ms·
I think you greatly misunderstood the article. There's no issue with optional<T>, nor is the article complaining that T* is a bad optional<T>. The problem is t
by kllrnohj 5y ago
I think you greatly misunderstood the article. There's no issue with optional<T>, nor is the article complaining that T* is a bad optional<T>.
The problem is that you can't have optional<T&>. So if you want to pass an optional reference to something, you're currently forced to pass T* instead (using null as the proxy for "not passed", of course). And thus, T* makes for a poor optional<T&>.
- kazinator 5y ago> no issue with optional<T> Didn't say there is (or, for that matter, that there isn't). The author does say there is an issue with it: he would like optional<T&> but cannot have it. (That, of course, is not optional's fault, though). > nor is the article complaining that T* is a bad optional<T>. But it is poor (not just in comparison to a fictitious optional<T &>). > So if you want to pass an optional reference to something, you're currently forced to pass T* instead (using null as the proxy for "not passed", of course). And thus, T* makes for a poor optional<T&>. 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. References in C++ are odd; they have limitations. For instance, you can't declare an array of them, either. To simulate an optional reference, we use a pointer, and we can wrap that in a class: class optional_int_ref { const int *maybe_int; // null if we aren't referencing an int, otherwise valid pointer }; Then of course we want that to be a template to make it generic. 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. Basically, you don't want optional<T &>, but a parallel optional_ref<T>: something that optionally references a value, and if so, that value is somewhere else. So, today, we could make optional_ref<T>. If we did so, then T * would be a poor optional_ref<T> for the same reasons that it's a poor optional_ref<T &> that we don't have. Therefore, T * is not the best optional we can have.
- MauranKilom 5y ago> Basically, you don't want optional<T &>, but a parallel optional_ref<T>: something that optionally references a value, and if so, that value is somewhere else. This exact consideration is discussed in the article and arguments are brought forth against it. I would love to give you benefit of the doubt, but you clearly didn't read the article.
- kazinator 5y agoIt's a long article; I read most of it, but skimmed some of it quickly toward the end. Thanks for pointing that out; see the "§ What about optional_ref<T>?" just before the conclusion (same name and all). I probably missed it because it has no code box; if I get tired of reading something long, I start to gravitate toward code rather than walls of text. optional_ref being "spelled differently" is a given. It has different semantics from optional, and doesn't replace it (as is noted) and so of course it deserves a different name. An optional reference to something (which itself isn't optional) isn't the same as an optional something (which either exists or doesn't). This is a fluff objection. Regarding the objection against duplicating code in the implementation for things like map: 1. So what? C++ is full of duplication. 2. All the same, perhaps the implementor could find a way to share some implementation bits between optional and optional_ref. I haven't tried a cut at it, but it doesn't seem self-evident to me that the only way to implement optional_ref is complete copy and paste from optional. The author has a valid points about there being issues with having to hard code either optional or optional_ref in places in the user code. Maybe a combind super_optional<bool ref, T> which goes to optional<T> if ref is false otherwise to optional_ref<T> could help. That is similar in spirit to the workaround, except the choice of "ref or not" isn't extracted from a T& versus T argument; it's an explicit template parameter. In the end the author's conclusion is indeed that "optional_ref<T> is a much better optional reference than T*, but it’s still a poor substitute", where by substitute I think he means "alternative for the nonexistent optional<T&>".
- deleted 5y ago[deleted]
- kazinator 5y ago
- 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.