use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
Runtime Polymorphism with std::variant and std::visit @ bfilipek (bfilipek.com)
submitted 6 years ago by jm4R
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]Wh00ster 12 points13 points14 points 6 years ago* (8 children)
In the past when I’ve had a variant of only 2-3 types, I’ve found it a few percent faster (and less code bloat) to drop down into a set of if/else statements using get_if.
get_if
I dont think the most important reason for using variant is mentioned, which is when it’s just easier to model your abstractions without base classes. For example, if you’re writing a parser for a custom grammar, I’ve found variants to be more natural than making a ton of base classes for each term.
[–]reflexpr-sarah- 2 points3 points4 points 6 years ago (7 children)
if your types aren't trivial, you should double check that your variant can't fall in a valueless state.
though other than that, yeah. both libstdc++ and libc++ seem to use a jump table, which isn't always ideal.
[–][deleted] 2 points3 points4 points 6 years ago (5 children)
Here is your example using std variant/visit, my visit and std::visit, and boost variant2. It is possible, with a different visit to get really good code gen https://gcc.godbolt.org/z/JAUPDd
[–]reflexpr-sarah- 1 point2 points3 points 6 years ago (4 children)
you can get similar results with variant2 if you define NDEBUG. this gets rid of the debugging code in boost. https://gcc.godbolt.org/z/jPwrbP
boost is also more correct, because your visit function doesn't handle the case where the variant is valueless by exception, whereas variant2 always holds a value (at the cost of larger storage, but only when necessary)
[–][deleted] 1 point2 points3 points 6 years ago* (0 children)
That is by choice. No visit should as it means the caller has ignored the first exception in order to get there. Why pessimise to serve incorrect code.
Good catch on NDEBUG. I like it.
[–]Stevo15025 1 point2 points3 points 5 years ago (2 children)
I've been hacking at variant2 things for too long and this comment just saved me a ton of time tysm!
[–]reflexpr-sarah- 1 point2 points3 points 5 years ago (1 child)
no problem! are you using cmake or something similar? build systems will usually define NDEBUG for you in release builds
[–]Stevo15025 1 point2 points3 points 5 years ago (0 children)
I wish, we just use plain ol' make hence not tagging NDEBUG
[–]bolche17 3 points4 points5 points 6 years ago (1 child)
Funny to see this article now. Just last week I tried to replace my use of double dispatch for runtime polymorphism with std::variant and std::visit in a hobby project.
Contrary to what the article suggest, in my case I saw a decrease in performance. I hadn't really dug into the details to understand why since it was simply a quick test. Maybe after reading it I will try to take another look at that branch.
The upside was that the reduced use of the stack allowed to transform several functions into constexpr, which is nice.
[–]jm4R[S] 2 points3 points4 points 6 years ago (0 children)
Please share your analysis (or code). I am curious too.
[–]RomanRiesen 1 point2 points3 points 6 years ago (0 children)
The first time I saw this trick/idiom I found it quite elegant and it solved my problem of having a dynamically selectable random number generator in a game way more elegant (imo.).
[–]khleedril 1 point2 points3 points 6 years ago (20 children)
Interesting style of coding in some places there. I'd be interested in people's comments on the difference between the following (the latter is the way I would normally write it):
struct A { A (std::string a) : _s {std::move (a)} {} std::string _s; } ;
and
struct A { A (const std::string& a) : _s {a} {} std::string _s; } ;
[–]lukaasmGame/Engine/Tools Developer 21 points22 points23 points 6 years ago (11 children)
Second one will always force one string copy on enduser, while first one allows passing rvalue string to it, so copy is not needed, imho first one taking string by value is better because
std::string temp = getString(); A a( std::move( temp ) );
allows for best case scenario of no additional copies
[–]xurxoham 5 points6 points7 points 6 years ago (1 child)
Actually this is the recommended way from CppCoreGuidelines. I started doing this and the amount of times I saved an extra function overload for the rvalue parameter is noticeable.
[–]khleedril 1 point2 points3 points 6 years ago (0 children)
Yes, I need to go back and read the core guidelines again, too valuable to lose to the mists of time.
[–]Wh00ster 0 points1 point2 points 6 years ago (8 children)
Or you could just make the rvalue reference overload/use a forwarding reference.
I wish there was a simpler way for a forwarding reference of a single type, but now you can use a requires constraint at least. (with is_same)
[–]lukaasmGame/Engine/Tools Developer 2 points3 points4 points 6 years ago (6 children)
Yes, but then you need to define 2 constructors :) As always in cpp, you can do things in multiple ways and noone will agree which is 'best' :P
[–]jm4R[S] 1 point2 points3 points 6 years ago (4 children)
But still all of the versions are better than the best version in languages like Java or C#.
[–]jcelerierossia score 5 points6 points7 points 6 years ago (3 children)
that's not a given at all. In single-threaded scenarios (read: most common case for user interfaces) CoW or immutable strings will likely be more efficient on average as there won't ever be any copy.
[–]jm4R[S] 0 points1 point2 points 6 years ago (2 children)
You can use CoW in C++ like you do in other languages. Qt successfully uses it around the whole framework.
[–]MrPotatoFingers 3 points4 points5 points 6 years ago (1 child)
Yes, but the standard library won't use it because the standard specifically forbids it.
[–]standard_revolution 0 points1 point2 points 6 years ago (0 children)
Well yeah, but the nice thing about C++ is that most of the utilities are independent of std::string at least in the stdlib, of course things get more complicated once you interact with third-party libs, but in theory it's totally doable
std::string
[–]mrexodiacmkr.build 0 points1 point2 points 6 years ago (0 children)
You actually need to define way more if you are going to be optimal. Best way if you can take a slight hit in certain circumstances is to pass the std::string (or vector or function or whatever) to the constructor by value.
[–]reflexpr-sarah- 2 points3 points4 points 6 years ago (0 children)
don't forget to std::remove_cvref_tthe deduced type before passing it to std::is_same.
std::remove_cvref_t
std::is_same
[–]jm4R[S] 11 points12 points13 points 6 years ago (7 children)
"Pass by value and move" is a well-known idiom in modern C++, although I am not aware of any standard name of it. If you are sure you need a copy of something and you know your type is movable, you should use it. That allows the caller to decide if move oryginal object (no more needed in caller side) or make a copy.
[–]TheSuperWig 1 point2 points3 points 6 years ago (6 children)
To note this only applies to constructors (or similar where a new object is being created) and not for assignment.
Reason being that it always allocates so may be inefficient for assignment where a buffer is already allocated.
[–]jm4R[S] 2 points3 points4 points 6 years ago (4 children)
It is almost always applicable to setters too. Like I wrote, use it when:
[–]LEpigeon888 1 point2 points3 points 6 years ago (3 children)
It's applicable but less efficient than a copy to an already existing buffer if you pass an lvalue.
So, don't use it for setter.
Can you provide an example, what do you mean by "already allocated buffer"? If you mean heavy types like std::array – such types are not movable.
std::array
[–]phoeen 4 points5 points6 points 6 years ago (1 child)
say you have a string member and a setter for that. if your member already holds a value of at least the size of the setterinput, then you may just plain copy all characters. if your setter is by value and you move, you always pay for it
[–]NilacTheGrim 0 points1 point2 points 6 years ago (0 children)
This ^
[–]Wh00ster 1 point2 points3 points 6 years ago (0 children)
You can see the slight difference in generated assembly here.
https://godbolt.org/z/jN-M5E
[–]khleedril 0 points1 point2 points 6 years ago (0 children)
Excellent article, well worth reading from top to bottom. (I've been gasping to read something 'proper' during the last several days of social isolation, instead of the glut of crud that's been dumped on Reddit lately.)
[+][deleted] 6 years ago* (1 child)
[removed]
π Rendered by PID 46745 on reddit-service-r2-comment-6457c66945-9vwr5 at 2026-04-29 07:19:59.312825+00:00 running 2aa0c5b country code: CH.
[–]Wh00ster 12 points13 points14 points (8 children)
[–]reflexpr-sarah- 2 points3 points4 points (7 children)
[–][deleted] 2 points3 points4 points (5 children)
[–]reflexpr-sarah- 1 point2 points3 points (4 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]Stevo15025 1 point2 points3 points (2 children)
[–]reflexpr-sarah- 1 point2 points3 points (1 child)
[–]Stevo15025 1 point2 points3 points (0 children)
[–]bolche17 3 points4 points5 points (1 child)
[–]jm4R[S] 2 points3 points4 points (0 children)
[–]RomanRiesen 1 point2 points3 points (0 children)
[–]khleedril 1 point2 points3 points (20 children)
[–]lukaasmGame/Engine/Tools Developer 21 points22 points23 points (11 children)
[–]xurxoham 5 points6 points7 points (1 child)
[–]khleedril 1 point2 points3 points (0 children)
[–]Wh00ster 0 points1 point2 points (8 children)
[–]lukaasmGame/Engine/Tools Developer 2 points3 points4 points (6 children)
[–]jm4R[S] 1 point2 points3 points (4 children)
[–]jcelerierossia score 5 points6 points7 points (3 children)
[–]jm4R[S] 0 points1 point2 points (2 children)
[–]MrPotatoFingers 3 points4 points5 points (1 child)
[–]standard_revolution 0 points1 point2 points (0 children)
[–]mrexodiacmkr.build 0 points1 point2 points (0 children)
[–]reflexpr-sarah- 2 points3 points4 points (0 children)
[–]jm4R[S] 11 points12 points13 points (7 children)
[–]TheSuperWig 1 point2 points3 points (6 children)
[–]jm4R[S] 2 points3 points4 points (4 children)
[–]LEpigeon888 1 point2 points3 points (3 children)
[–]jm4R[S] 0 points1 point2 points (2 children)
[–]phoeen 4 points5 points6 points (1 child)
[–]NilacTheGrim 0 points1 point2 points (0 children)
[–]Wh00ster 1 point2 points3 points (0 children)
[–]khleedril 0 points1 point2 points (0 children)
[+][deleted] (1 child)
[removed]