3 ms·
I do get that it's the type-safe approach but your resulting code looks more complicated than what I did (to me). Still, thanks for sharing so that other peopl
by eatonphil 5y ago
I do get that it's the type-safe approach but your resulting code looks more complicated than what I did (to me).
Still, thanks for sharing so that other people can see for themselves.
One of the biggest turnoffs about std::variant to me (which isn't relevant here) is that you can't name the types so the hacks for having multiple of the same type in std::variant look even hairier.
- gravypod 5y agoA nice follow up would also be looking at std::string_view as this has the potential to save a lot of memory.
- eatonphil 5y agoSince I'm unfamiliar with the underlying concept, could you give an example of how you could see that being used?
- gravypod 5y ago`std::string_view` is essentially something like this: struct string_view { char *data; size_t length; } It is a pointer to a subset of an existing string. It has all of the existing features of `std::string` but passing it around is zero copy. As long as the original memory allocation exists your `string_view`s are still valid. Also, it has an implicit constructor from `const std::string` and `const char #` allowing you you define a single function like `Thing ParseThing(std::string_view line)` and accept `char #` and `std::string` as an input. More examples are here: https://abseil.io/tips/1 https://abseil.io/tips/1 # -> *. HN formats bad
- Arnavion 5y ago\* (backslash asterisk) will escape the asterisk. >Also, it has an implicit constructor from `const std::string` and `const char *` allowing you you define a single function like `Thing ParseThing(std::string_view line)` and accept `char *` and `std::string` as an input.
- jcelerier 5y agoevery function where you are reading from a string without writing to it or saving it, you can use std::string_view. Same for vector / array: anything non-owning, read-only should use std::span instead.
- jcelerier 5y agoit's not only type-safe, it uses much less memory, takes less time to construct and does not duplicate the "null" state: - your JSONStruct takes 160 bytes (on 64-bit systems with libstdc++), the variant one takes 56, almost three times less. - it needs std::optional<T> for each member to avoid construction, while std::variant does that by default. But the compiler still have to initialize all these optionals to their default state. - you need on every access two branches: * one for the type switch * one for the optional the variant only has one level of indirection.
- eatonphil 5y agoThat's fair. I assumed it would be clear to anyone who knows C++ better than I that the point of this post wasn't exactly performance. Actually I was most interested in just how simple and readable I could make it. But I didn't say that in the post anywhere. Will add.
- jcelerier 5y ago> I assumed it would be clear to anyone who knows It's just not possible to assume that at all on the internet. Every year I have students who learn from blog posts like this for instance.
- gravypod 5y agoAs someone who does quite a bit of C++ recently: for most uses readability is king. If you did want squeeze out the extra performance you could also do something where you store `std::variant<>` inside a struct and provide an API like this: if (auto int_value = value.i()) { // *int_value == your int } and expose a `std::variant<> &variant();` for use cases where you want the more complex/faster stuff.
- tcbawo 5y agoUsing variant as the storage type while providing a nice public accessor API makes sense given the huge difference in semantics between a struct containing optional fields and a variant.
- quietbritishjim 5y agoRather than using std::visit, you can just use a chain of if statements with get_if [1]. You keep the most important benefits of std::variant but the code is much more readable (IMO). [1] https://news.ycombinator.com/item?id=25316192 https://news.ycombinator.com/item?id=25316192
- jcelerier 5y agoInteresting, I find the list of of ifs much less easy on the eyes. I wonder why that is.
- quietbritishjim 5y agoAgreed that it's a personal preference. If you geniunely have a standalone function, like print_type shown here, then std::visit seems roughly even with std::get_if to me (but I'd tend to use the latter for consistency with my other code). std::visit would clearly come out ahead if you had some sort of complex nested variant and you called out to other visitors. get_if is clearly ahead IMO if you're using a variant in passing in a broader function, and especially if you when you want to use control flow (if you return in an if branch you return from the wider function).
- jcelerier 5y agoYes, this case (checking for a type and returning early) is pretty much my only usage of get_if (and in this case it makes a lot of sense)