I think using this feature is the wrong advice. Frankly I think much of modern C++ should be rejected. If you want to use a language like with those features then fricken switch language! There are countless better alternatives today: Rust, Swift, D, Haskell etc.<p>Many are stuck on C++ for legacy reasons. I have worked in such large C++ legacy systems for many years in the past. The average programmer simply cannot deal effectively with this modern C++. It is too complex.<p>I’ve been down that road being exited about new C++ features only to realize that I’ve actually reduced the productivity of my co-workers.<p>Often I wonder if C++ programmers all suffer a Stockholm syndrome. They have come to sympathize with their hostage taker C++, making up excuses for the many ways C++ abuse and terrorize them.<p>I go to these C++ conference talks in occasion and I see people in ecstatic praise about how some genius C++ guru came up with an elaborate convoluted solution to something which is like two lines of code in a sane programming language.<p>Seriously I think C++ has drained so much of their brainpower that they have simply not been able to look outside and see how the grass is greener everywhere else.
I've been writing C++ since 1990. I make a good living from a little C++ app (500KLOC) that sells in fifty countries. I love the ultra-static typing. It's saved my bacon many a times.<p>Long ago "modern" C++ crossed into a territory that I will never understand or use. STL is the fanciest stuff I write. Code needs to be maintainable. If I have to hire geniuses to collaborate on my code, that's not going to be cost-effective. So I use a conservative subset, and thank my lucky stars I don't need to pay attention to the latest exotica.
As a long-time user of C++ variants with a home-grown tool much like the article’s make_visitor, I think there’s a much bigger problem with C++ variants: the sub-types don’t have <i>names</i>.<p>If you genuinely want your variant to just be a mildly polymorphic object, this is okay. But you probably don’t. Imagine the classic use of variants for a parse tree:<p>variant<string, shared_ptr<Node>><p>Okay, presumably the string is a token and the Node is a subtree. This is already a bit unpleasant, but at least it’s serviceable. But then you discover that you really want tokens and symbol names to be separate. You try:<p>variant<string, string, shared_ptr<Node>><p>And you lose, because the two unnamed string cases are ambiguous. To work around this, you need to wrap the strings in newtypes, which is quite verbose in C++. And you start to wonder why, after all these years, C++ hasn’t sucked it up and come up with real sum types in the language.<p>(For those who are too stuck in C++ land, this problem simply does not exist in a language like Rust.)
The post raises some good points, but I nonetheless think that C++ is a better language for having std::variant. It can result in some very clear, expressive code, despite the boilerplate and dabbling with more advanced language features that it necessitates.<p>Indeed, from the article: "In spite of all of this, I’ll be busy encouraging my coworkers to use variant if anybody needs me. Sum types are such a useful concept that they’re worth the pain[...]"
We got here because adding library features is a lot easier and less risky than adding language features. Work on pattern matching [1] is ongoing, but the bar for entry for a language feature is much higher and as such takes a longer time.<p>1. <a href="http://wg21.link/p1371" rel="nofollow">http://wg21.link/p1371</a>
Beyond the ergonomics, `std::variant` is horribly outperformed by basic type erasure mechanisms or inheritance. Every time I've tried to use `std::variant` I've been unhappy with the runtime performance vs any other way to solve this problem (the compile time performance is expectedly atrocious compared to any other method).<p>So you've got poor ergonomics, poor compilation performance, bloated code size, and poor runtime performance. I've written an enormous amount of C++ code from applications to libraries to system development. I literally have never found a place where `std::variant` has any positives that can't be written a different, clearer way with drastically better compile time and run time performance.
Visit the last time this was discussed here:<p><a href="https://news.ycombinator.com/item?id=15249994" rel="nofollow">https://news.ycombinator.com/item?id=15249994</a>
As the article says:<p>- you can write 10LOC to have a lambda visitor. Idk why the standard doesn’t do this for you but it’s not a big deal<p>- sum types are super useful and your language will want some sort of niceties/extra characters to deal with them (and all options will be better than unions which are an unsafe mess)<p>So ... what’s the big issue? C++ is complicated? It’s a language designed to give the programmer full control when they want it. You don’t have to constantly use every bit of it.
Its probably time to give C++ a rest and stop evolving it. We've probably long since passed the point where any evolution gives a net benefit to engineers, and its time to let other languages take over.
The problem with C++ is really the standards committee overcomplicating things. They've done some important work, like the memory model, but they don't have the confidence to make the decision quickly enough.<p>Compare template constraints in D and C++. C++ ends up with concepts after something like 25 years in the making, and they add huge amounts of syntax and bloat, whereas in D it's just an if statement after before the template body.<p>The way static if was considered was bizarre too
I usually just use switch(std::variant:index()) and then std::get<int>(). Which worked reasonably well. But then I stopped using std::variant altogether, because in the end it never gave enough benefits.
These days I use reinterpret_cast and cast away all my problems.
On a tangent, how do you do sum types in java? I recently wanted to use them and all I could figure out was some subclasses and `instanceof` as poor man's pattern matching.
I actually prefer the overloads or constexpr branches to make_visitor because it's easier to see what's going on.<p>Anyway, until C++ gets pattern matching for the simple cases make_visitor is the best we can do.<p>If you want advanced variant use cases you can always use boost::variant (v1) which supports multivisitation, which coupled with templates is exceptionally powerful.<p>If you want to go even further with open multimethods you can checkout the yomm2 library.<p>As always C++ gives you options
I don’t think any of the approaches in this article are appropriate for the stated problem. Specifically, <i>parsing</i> data from an INI/JSON/text file (or TLV-like encoding, predefined format/protocol, etc.), the parser can produce appropriate structures for the underlying data. This is the phase when you analyze (and likely validate) the input data, so you’d know the appropriate type after parsing.<p>You may want your parse tree to produce objects instead of fundamental C++ types (e.g. with functions like isNull(), isValid(), etc.). A common approach might be to produce a simple AST where each node includes just the fundamental type you’re interested in. Then you can simply follow the visitor pattern and write visitors for things like serializing/deserializing, generating/traversing/executing trees/graphs/code, etc...<p>Perhaps I’m missing something though? A more concrete definition of the problem would be helpful...
I actually think the last version, using a single lambda with constexpr ifs inside, looks completely reasonable.<p>But yeah the first time I had to use boost::variant (which is what the version in the standard library is based on) I thought the visitor was too much boilerplate. Things have gotten better since then, but many people are not even on C++17 yet ):
In many cases you can get away with just using a struct with a tag (no unions). Yes, it wastes memory, and isn't as safe as a proper sum type, but at least it's memory-safe for C++ objects and you can use a normal switch statement. Compiler warns if your switch isn't exhaustive. Compile times are fast too.
With C++17's compile-time conditionals, plus good old C preprocessor macros, you could do this:<p><pre><code> #define MATCH_VARIANT(x) [](auto& x)
#define CASE_VARIANT(x, T) constexpr (std::is_same_v<std::decay_t<decltype(x)>, T>)
MATCH_VARIANT(arg) {
if CASE_VARIANT(arg, string) {
printf("string: %s\n", arg.c_str());
// ...
}
else if CASE_VARIANT(arg, int) {
printf("integer: %d\n", arg);
// ...
}
else if CASE_VARIANT(arg, bool) {
printf("bool: %d\n", arg);
// ...
}
}
</code></pre>
(MATCH_VARIANT could be extended to allow capturing vairables, or just omit that macro, it saves less typing than CASE_VARIANT anyway.)
My field barely use C++, so i wonder : do people still have the feeling that "C++" is not going anywhere, or is it just C that's unavoidable ?<p>I feel like except maybe in complex video-game engines, C++ is slowly but surely getting replaced by more adapted languages.
If anyone is interested, we had a small utility in one of our C++ code-bases to leverage ADTs where it made sense. Here is the implementation.<p><a href="https://github.com/insieme/insieme/blob/master/code/utils/include/insieme/utils/adt.h" rel="nofollow">https://github.com/insieme/insieme/blob/master/code/utils/in...</a><p>Some tests illustrating the usage can be found here:<p><a href="https://github.com/insieme/insieme/blob/master/code/utils/test/adt.cc" rel="nofollow">https://github.com/insieme/insieme/blob/master/code/utils/te...</a>
Given all this, use a dumb old macro to make a simpler interface with a macro that expands to type safe code. That will save a lot of unnecessary syntactical noise and overwinter you until better pattern matching support comes along.
There is a point, but it is overstretched. make_overloads is actually a cool trick. Yes, it would be nice if there was a version of this in the standard library, but then again, it is just a few lines of magic. That will not be the first lines of magic in your C++ codebase.<p>If you compare the sum type and pattern matching story with modern languages, sure, you will find C++ is lacking. And it is. However, such a comparison is ignoring history.<p>I actually like variant. It is the best sum type we have in C++.