TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Std::visit is everything wrong with modern C++

201 pointsby foobover 7 years ago

27 comments

maxlybbertover 7 years ago
From the article:<p>&gt; it’s completely bonkers to expect the average user to build an overloaded callable object with recursive templates just to see if the thing they’re looking at holds an int or a string.<p>You don&#x27;t have to: <a href="http:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;utility&#x2F;variant&#x2F;holds_alternative" rel="nofollow">http:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;utility&#x2F;variant&#x2F;holds_alter...</a> (and <a href="http:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;utility&#x2F;variant&#x2F;get" rel="nofollow">http:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;utility&#x2F;variant&#x2F;get</a> to access the value).
评论 #15252071 未加载
评论 #15252182 未加载
评论 #15252129 未加载
评论 #15251829 未加载
trendiaover 7 years ago
&gt; The fact that we still handle dependencies in 2017 by literally copy-pasting files into each other with #include macros is obscene.<p>Historically, C++ used includes so that it could be compatible with C. In the future, modules can be used which avoid many of the problems with includes [0].<p>[0] <a href="http:&#x2F;&#x2F;www.open-std.org&#x2F;jtc1&#x2F;sc22&#x2F;wg21&#x2F;docs&#x2F;papers&#x2F;2017&#x2F;n4681.pdf" rel="nofollow">http:&#x2F;&#x2F;www.open-std.org&#x2F;jtc1&#x2F;sc22&#x2F;wg21&#x2F;docs&#x2F;papers&#x2F;2017&#x2F;n468...</a>
评论 #15252998 未加载
JoshTriplettover 7 years ago
I agree completely with everything in this article. But in addition, I think std::variant also misses the point of sum types in a big way.<p>Sum types don&#x27;t just store values of different types. They store different states, with associated data. So, for instance, consider the following simplistic expression AST; how would you store it in a std::variant?<p><pre><code> enum Expr { Number(usize), Negate(Expr), Add(Expr, Expr), Sub(Expr, Expr), Let(String, Expr, Expr), Var(String), }</code></pre>
评论 #15251305 未加载
评论 #15251328 未加载
评论 #15251558 未加载
评论 #15251515 未加载
评论 #15251288 未加载
评论 #15251357 未加载
评论 #15251941 未加载
int_19hover 7 years ago
The reason why we have std::visit the way it is, is because that&#x27;s the way it worked in Boost Variant, which is the basis for the proposal.<p>The reason why it&#x27;s the basis, is because it&#x27;s a time-tested, proven and stable solution that has been around since 2002.<p>The reason why it&#x27;s so ugly, is because that&#x27;s the best you could do in C++ back in 2002.<p>So, there&#x27;s a perfectly rational explanation for all this - it&#x27;s not &quot;insane&quot;. It is unfortunate that they didn&#x27;t come up with a better API that would make use of new language features, but it&#x27;s not like someone deliberately set down to design the more convoluted older API just to confuse people.
any1over 7 years ago
Sum types can actually be implemented quite effectively using X-macros in both C and C++. In fact, I feel like they&#x27;re simpler and more intuitive than this variant stuff.<p>Edit: Let&#x27;s use the same example.<p><pre><code> #define SETTINGS \ X(string, str) \ X(int, num) \ X(bool, b) struct Setting { union { #define X(type, name) type name; SETTINGS #undef X }; enum Type { #define X(type, ...) t_ ## type, SETTINGS #undef X }; Type tag; }; </code></pre> Printing settings like in the example becomes this:<p><pre><code> void printSettings(const Setting&amp; s) { switch(s.tag) { case t_string: printf(&quot;A string: %s\n&quot;, s.str.c_str()); break; case t_int: printf(&quot;An integer: %d\n&quot;, s.num); break; case t_bool: printf(&quot;A boolean: %d\n&quot;, s.b); break; } } </code></pre> We can also load more things into the x-macro, so it&#x27;s possible to define the switch cases above just like in the structure definition. We could add a third parameter called full_name:<p><pre><code> void printSettings(const Setting&amp; s) { switch(s.tag) { #define X(type, name, full_name) \ case t_ ## type: std::cout &lt;&lt; &quot;A &quot; full_name &quot;:&quot; &lt;&lt; s.name &lt;&lt; &quot;\n&quot;; #undef X } } </code></pre> Disclaimer: I have not compiled or run any of this code.
评论 #15253439 未加载
option_greekover 7 years ago
Half the way into the article, I felt like crying. Is it just me or is the standards committee actively trying to reduce the number of existing C++ programmers. I think we are better off with boost than learning this new stuff. I hope the people in standards committee will lose their C#&#x2F;Java&#x2F;&lt;insert cool language&gt; envy and be more selective in what they want to add to standards.
评论 #15251451 未加载
评论 #15253417 未加载
评论 #15252991 未加载
评论 #15253310 未加载
评论 #15252720 未加载
评论 #15252173 未加载
hoytechover 7 years ago
I looked into this recently, and this is the implementation I ended up choosing:<p><a href="https:&#x2F;&#x2F;github.com&#x2F;mapbox&#x2F;variant" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;mapbox&#x2F;variant</a><p>It has a very handy &quot;match&quot; method that addresses the issue raised in this blog post.<p>They&#x27;ve also compiled many links to other variant implementations, as well as a bibliography on the standardisation efforts:<p><a href="https:&#x2F;&#x2F;github.com&#x2F;mapbox&#x2F;variant&#x2F;blob&#x2F;master&#x2F;doc&#x2F;other_implementations.md" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;mapbox&#x2F;variant&#x2F;blob&#x2F;master&#x2F;doc&#x2F;other_impl...</a><p><a href="https:&#x2F;&#x2F;github.com&#x2F;mapbox&#x2F;variant&#x2F;blob&#x2F;master&#x2F;doc&#x2F;standards_effort.md" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;mapbox&#x2F;variant&#x2F;blob&#x2F;master&#x2F;doc&#x2F;standards_...</a>
bluejekyllover 7 years ago
&gt; How do you teach this without overwhelming a beginner with all this other… stuff?<p>&gt; Is it expected to be common knowledge for your everyday programmer?<p>&gt; (And if the goal of adding variant to the standard library isn’t to make it a tool for the masses, shouldn’t it be?)<p>These are great questions for any piece of software. Especially features being introduced in a language.
评论 #15265736 未加载
评论 #15254513 未加载
tlbover 7 years ago
You can use variants just fine without a visitor. Like,<p><pre><code> std::variant&lt;string, int, bool&gt; v; ... if (auto pstr = std::get_if&lt;string&gt;(&amp;v)) { cout &lt;&lt; *pstr &lt;&lt; endl; } else if (auto pint = std::get_if&lt;int&gt;(&amp;v)) { cout &lt;&lt; *pint &lt;&lt; endl; } else if (auto pbool = std::get_if&lt;bool&gt;(&amp;v)) { cout &lt;&lt; *pbool &lt;&lt; endl; } else { count &lt;&lt; &quot;null&quot; &lt;&lt; endl; } </code></pre> which is not much worse than the pattern matching syntax.
评论 #15251899 未加载
kronaover 7 years ago
I don&#x27;t know why the author is so disparaging of <i>if constexpr</i>; I think it&#x27;s going to push c++ metaprogramming in a direction that makes the more powerful aspects of the language easier to understand for beginners.<p>Surely a good thing.
AlexCoventryover 7 years ago
The struct solution seems OK to me, and the alternatives don&#x27;t seem to accomplish much, brevity-wise. What&#x27;s the problem with it?
评论 #15251372 未加载
评论 #15251914 未加载
ChrisSDover 7 years ago
So the short version is that the C++ committee accepts a partial feature set despite key features not being ready in time?<p>Perhaps they expect Boost to work round it until the next standard is released...
评论 #15255699 未加载
bitLover 7 years ago
Seems like a design pattern from Java which often are badly converted functional programming snippets into OOP. I once loved C++, now I can&#x27;t force myself to read the code anymore... Please add some monads there to destroy my hope for humanity once for all!<p>I think maintainers of C++ have a case of &quot;functional programming&quot; envy.
评论 #15251831 未加载
评论 #15251512 未加载
评论 #15251369 未加载
Davidbrczover 7 years ago
Quick survey<p><pre><code> std::variant&lt;std::string,bool&gt; v {&quot;abc&quot;}; </code></pre> Q: Which type is used ?<p>(Since I&#x27;m asking a question, you know there is a gotcha). Answer: &quot;abc&quot; is const char*, which can be converted to bool and is picked because the way variant is designed.
slavik81over 7 years ago
So, if you really hate making a struct each time, you drop make_visitor into the project&#x27;s util.h and never worry about it again. I don&#x27;t see the big deal.
评论 #15251715 未加载
kxyvrover 7 years ago
Funny enough, std::visit was one of the features of c++17 that I was looking forward most to. Something that I don&#x27;t entirely understand, though, and the author brings up is the lack of a function like make_visitor. Does anyone understand why or was there a late addition of a function that I&#x27;m not aware of? And, yes, std::visit is nonideal, but I do think it to be a much better option to using double dispatch and the visitor pattern, which is what we had to do before.<p>More generally, I write numerical software and I do with there was a better option for writing this software outside of C++, but I don&#x27;t see one right now. Specifically, C++ gives us direct access to the c-api of other languages and some pretty powerful tools to handle that. As such, if we want our software to work across multiple languages like Python, MATLAB&#x2F;Octave, or a variety of other languages, C++ appears to be the best fit. Yes, it&#x27;s possible to hook something like a Python code to MATLAB&#x2F;Octave, but it&#x27;s hard because Python and MATLAB&#x2F;Octave handle memory in different ways. For example, they differ on how and when objects are collected by the garbage collector, so it makes it hard to use a Python object directly in MATLAB&#x2F;Octave. In C++, we have enough tools to handle hooking C++ objects and items to other languages. Certainly, it&#x27;s a pain, but I contend it&#x27;s easier than to hook two other languages together through the c-api, but I find this more difficult to manage and we now have a bunch of additional code to maintain as well. As such, as many disadvantages as the language has, I appreciate new features like std::visit because it means that I can write easier code for my algorithms and still be able to hook to others.
评论 #15253066 未加载
评论 #15255670 未加载
mark-rover 7 years ago
I&#x27;ve been programming C++ for 20 years, and since C++11 the only feature I&#x27;ve seen that&#x27;s worth the cognitive load is <i>auto</i>. Everything else just seems overly complicated. When I compare it to how easy things are in Python, I cry.
评论 #15251703 未加载
评论 #15252201 未加载
评论 #15254938 未加载
评论 #15252017 未加载
评论 #15251560 未加载
评论 #15259597 未加载
ausjkeover 7 years ago
the new c++ is great in that it is evolving fast, but I feel it is extremely hard to read, the readability of the language is diminishing by each newer version.
评论 #15251425 未加载
lomnakkusover 7 years ago
I think all the answers will probably come when C++17 support is good enough. See the example at [1], in particular the &quot;overloaded&quot; bit.<p>I <i>think</i> my current GCC 7.2 should support it, but I don&#x27;t think my current Clang 4.0.1 does. EDIT: Just tested and I can confirm that.<p>[1] <a href="http:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;utility&#x2F;variant&#x2F;visit#Example" rel="nofollow">http:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;utility&#x2F;variant&#x2F;visit#Examp...</a>
kelvin0over 7 years ago
Javascript and other dynamic languages are leaning towards type safety and other static checking tools. C++ and other compiled languages have strong types , but need and std::variant (and similar constructs) to add flexibility and boost productivity. The Yin and the Yang, looking to balance themselves into perfect programmer bliss.
amlutoover 7 years ago
I had a perfectly functional lambda-based visitor working in C++11. I don&#x27;t see the problem. I can try to dig it up.
lsh123over 7 years ago
I might be missing something big but the &quot;match (theSetting) {...}&quot; example can be mapped to C++ as:<p>switch(setting-&gt;tag) {<p>case Str:<p><pre><code> &#x2F;&#x2F; do something with setting-&gt;str break; </code></pre> case Int:<p><pre><code> &#x2F;&#x2F; do something with setting-&gt;n break; </code></pre> case Bool:<p><pre><code> &#x2F;&#x2F; do something with setting-&gt;b break; }</code></pre>
评论 #15251712 未加载
评论 #15252079 未加载
makecheckover 7 years ago
No doubt that std::visit appears to be a mess but why not call std::get&lt;a_type&gt;(a_variant) and trap bad_variant_access exceptions? It would still be a bit annoying to exception-wrap each attempt but it seems cleaner than any of the std::visit alternatives.
评论 #15252228 未加载
jasonmaydieover 7 years ago
Is the author complaining that the process is too complicated? This is typical of the c++ world, other languages make it easy but c++ isn&#x27;t other languages.
iammyIPover 7 years ago
C++ is a meta language based on C. You can pick the features you want to use.
Animatsover 7 years ago
&quot;Sum types&quot;. Hey, let&#x27;s give an old concept a new name. Those are called discriminated variant types, and they first appeared in Pascal. They&#x27;re a straightforward concept, and can be implemented easily at the language level.<p>The big problem with C++ is that the template fanatics took over. Templates are a crappy programming language - bad syntax, confusing semantics, and tough debugging. But there&#x27;s no way to stop people from extending the language via templates. Hence Boost, and &quot;you are not supposed to understand this&quot; templates.<p>(I fear that Rust is going down the same rathole.)
评论 #15251579 未加载
clishemover 7 years ago
This blog post is not to be taken seriously in my opinion. For one thing, `printf` is obsolete in C++. This is how you should output values in a tagged union:<p><pre><code> std::variant&lt;size_t, std::string&gt; var = &quot;test&quot;; std::visit([](auto &amp;&amp;val) { std::cout &lt;&lt; val; }, var); </code></pre> If you also want to print the name of the type of the variable, along with the value itself, well, C++ doesn&#x27;t have reflection (yet). So you&#x27;re going to have to write a function that takes a value and returns its type as a string, which you can already do using the typeid operator. This is basically implementing reflection yourself, it is cumberstone but doesn&#x27;t require advanced template programming.<p>There no need for any of the madness with explicit types inside the visitor lambda, which is deemed as neccesary by the author.<p>Edit: here&#x27;s another way to map types to strings. So no templates necessary at all for this entire problem.<p><pre><code> std::map&lt;std::type_index, std::string&gt; typeIdxToString; typeIdxToString[typeid(std::string)] = &quot;string&quot;; typeIdxToString[typeid(int)] = &quot;int&quot;; &#x2F;&#x2F; ... </code></pre> Edit2: Turns out C++ has some form of reflection after all. You can just use:<p><pre><code> typeid(val).name() </code></pre> If your compiler supports pretty names.
评论 #15252109 未加载
评论 #15251354 未加载
评论 #15251349 未加载
评论 #15251333 未加载
评论 #15251671 未加载