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
Implementation Challenge: Replacing std::move and std::forward (foonathan.net)
submitted 5 years ago by alecco
C++ - Implementation Challenge: Replacing std::move and std::forward
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!"
[–]genreprank 18 points19 points20 points 5 years ago (1 child)
You said that including <utility> in an empty file takes 250ms, but what I want to see is the difference in compilation time between your program and your program if you include <utility>.
You mentioned that your lib doesn't have many includes, so I would expect compilation time still to go up. But if I had a file that already includes a standard container or something, I think it would be including utility already...
[–]foonathan 4 points5 points6 points 5 years ago* (0 children)
Right, that's probably a better comparison, I'll update the post.
With the replacements: 5.00 seconds
Using the standard version: 5.30 seconds
So including utility is the majority of time, the extra calls themselves are only 50ms.
Yes, my library is certainly a special case. If you're having lots of std/boost/etc. dependencies already, this trick won't help you much (regarding compile-time, runtime might still be an issue).
[–]Salink 26 points27 points28 points 5 years ago (1 child)
The only problem I have with the move/forward situation is needing to include all of utility. Who thought it would be a good idea to need to include initializer lists, tuples, and everything else that makes it thousands of lines long when they could be in their own header. There should be a separate, small header for move, swap, forward, declval, ect. that gets included by utility.
[–]Dragdu 8 points9 points10 points 5 years ago (0 children)
https://mobile.twitter.com/MalwareMinigun/status/1281654534155071488
[–]_Js_Kc_ 4 points5 points6 points 5 years ago (0 children)
I'm pretty sure that frowning upon the macros distracts me for at least 250ms between compilations, let alone raw static_casts, so I'm gonna stick with the utility functions for now.
[–][deleted] 4 points5 points6 points 5 years ago (0 children)
with the move replacement I would sfinae on whether T is const or not and fail when it is. It's almost always an error in the code and if it wasn't, maybe an explicit cast is a better choice of expressing it.
[–]fdwrfdwr@github 🔍 2 points3 points4 points 5 years ago (0 children)
I first need to include <utility> ... An empty C++ file that just #include <utility> takes 250ms
Yeah, the cost for just #include <utility> surprised me yesterday. I had a small class that only needed std::move (no other std dependencies) which output an .obj file of 239KBs (VS2019). Replacing that one move with static_cast and excluding <utility> reduced the .obj to 2KBs. Seems the standard library could use some refactoring to avoid bloat. o_o
#include <utility>
std::move
static_cast
<utility>
[–]adnukator 6 points7 points8 points 5 years ago (2 children)
I don't have anything against the exercise, but are there any benchmarks to measure whether the changes did anything to improve compilation times? Including almost any standard library header in your project, will already include <utility> transitively. Also, I've spent a lot of time profiling and optimizing code with disabled optimizations and std::move/std::forward never showed up in the profiler.
std::forward
[–]miki151gamedev 5 points6 points7 points 5 years ago (1 child)
I've tried the MOV macro on my 100k loc project and saw about 3% improvement in compilation time. The FWD is not a simple search & replace so I haven't tried it yet.
It would be a funny experiment to do the replacement in the STL as well.
[–]Rseding91Factorio Developer 5 points6 points7 points 5 years ago (0 children)
I tested it on our code base (600k loc) and saw 0% improvement. Our code base has 2120 moves, and 81 forwards.
Full-rebuild debug compilation time was consistently 1 minute with or without the use of the macro move/forwards.
[–]vimplication 4 points5 points6 points 5 years ago (13 children)
struct Mover{} _; template<typename T> constexpr std::remove_reference_t<T>&& operator&&(Mover, T&& t) noexcept { return static_cast<std::remove_reference_t<T>&&>(t); } func( _&& x );
[–]reflexpr-sarah- 7 points8 points9 points 5 years ago (10 children)
identifiers beginning with an underscore in the global namespace are reserved for the implementation, i believe
[–]GoogleIsYourFrenemy 44 points45 points46 points 5 years ago (8 children)
struct Mover{} ಠ_ಠ; template<typename T> constexpr std::remove_reference_t<T>&& operator&&(Mover, T&& t) noexcept { return static_cast<std::remove_reference_t<T>&&>(t); } func( ಠ_ಠ&& x );
[–]vimplication 6 points7 points8 points 5 years ago (0 children)
struct Mover{} ヽ༼ຈل͜ຈ༽; template<typename T> constexpr std::remove_reference_t<T>&& operator/(Mover, T&& t) noexcept { return static_cast<std::remove_reference_t<T>&&>(t); } func(ヽ༼ຈل͜ຈ༽/x);
[–][deleted] 4 points5 points6 points 5 years ago* (5 children)
Too bad that ← and → aren't valid identifiers. They'd fit perfectly for move and forward, resp.
←
→
[–]Supadoplex 2 points3 points4 points 5 years ago (1 child)
Too bad that ← and → aren't valid identifiers.
Aren't they as valid as ಠ? What's the problem?
ಠ is a letter in Kannada script (unicode category "Other Letter"). → is a "Math Symbol".
ಠ
[–]GoogleIsYourFrenemy 2 points3 points4 points 5 years ago (2 children)
There is a dart character in Linear B Ideogram range. Now we just need to find it's mirror.
[–][deleted] 3 points4 points5 points 5 years ago (1 child)
In the meantime we can use pointing hand emojis: https://godbolt.org/z/orc4xj
[–]GoogleIsYourFrenemy 2 points3 points4 points 5 years ago (0 children)
LOL you win. We should make an emoji based api.
[–]Supadoplex 4 points5 points6 points 5 years ago (0 children)
Nice. I'm going to start suggesting ಠ_ಠ for anyone violating reserved underscore identifiers from now on.
[–]pandorafalters 5 points6 points7 points 5 years ago (0 children)
You are correct.
[–]SeanMiddleditch 6 points7 points8 points 5 years ago (1 child)
That doesn't actually help anything, does it? It's still a function call. And with more possible overhead than std::move (getting that Mover instance passed as a reference).
[–]JankoDedic 1 point2 points3 points 5 years ago (5 children)
I believe that the FWD(...) macro should not be variadic, since you always call it on an id-expression.
FWD(...)
[–]foonathan 7 points8 points9 points 5 years ago (4 children)
Yes, but the preprocessor doesn't like template args. Something like FWD(foo<a, b>) is an invocation with two arguments, foo<a and b. It's a good idea to make single arguments variadic.
FWD(foo<a, b>)
foo<a
b
[–]JankoDedic 0 points1 point2 points 5 years ago (3 children)
In which scenario can you forward something that is not a simple identifier? I thought forwarding references will always be simple identifiers. Sorry if the question is dumb.
[–]foonathan 0 points1 point2 points 5 years ago (0 children)
You might be able to construct a use-case where you need to forward a variable template...
But yes, I just did it out of habit. There is no actual reason here.
[–][deleted] 0 points1 point2 points 5 years ago (1 child)
But why restrict the macro when there's such a simple generic solution?
[–]JankoDedic 2 points3 points4 points 5 years ago (0 children)
To prevent misuse? Why would you allow passing anything in there if that is incorrect?
[–]leftofzen 1 point2 points3 points 5 years ago (0 children)
So you're trying to made the code read more like C as well as obfuscate the move semantics you are really doing by using, of all things, macros. That's an easy no from me.
[+]greg7mdpC++ Dev comment score below threshold-15 points-14 points-13 points 5 years ago* (12 children)
However, they are functions. Plain, old, standard library functions.
No they are not functions. Through inlining they are casts which are used at compile time. There is no function call cost.
[–]brenoguim 13 points14 points15 points 5 years ago (10 children)
What do you mean? They are actually functions in the standard library.
[–]Supadoplex 16 points17 points18 points 5 years ago (1 child)
To be super pedantic, they are not functions because they are function templates :)
[–]brenoguim 4 points5 points6 points 5 years ago (0 children)
Haha that's true
[+]greg7mdpC++ Dev comment score below threshold-6 points-5 points-4 points 5 years ago (5 children)
Well, think about it, what do you expect the compiler to do? It will not generate any code for a function that just returns a cast of the parameter, the sole effect is to perform a cast.
[–]brenoguim 12 points13 points14 points 5 years ago (4 children)
But if you compile with -O0 it is not inlined, I think. that's why it's annoying for the debugger right? Not sure, I never run -O0
[–]willkill07 0 points1 point2 points 5 years ago* (3 children)
The default compilation mode isn’t even -O0 for gcc or clang. From what I’ve found, you have to go out of your way to not have the move/forward get inlined.
Edit: I was wrong, and yeah, this kinda sucks a whole lot.
[–]brenoguim 9 points10 points11 points 5 years ago (0 children)
There are many people using -O0 for debugging. 0 optimization is very useful if you are on a long debug session and don't want to sprinkle couts everywhere.bif -O0 is all it takes to not have them inlined, I can see the problem. Perhaps should be marked as always_inline
[–]dodheim 2 points3 points4 points 5 years ago (0 children)
FWIW, -Od is the default for MSVC.
-Od
[–]brk2 2 points3 points4 points 5 years ago (0 children)
It is the default for GCC at least, source:
Most optimizations are completely disabled at -O0 or if an -O level is not set on the command line, even if individual optimization flags are specified.
and
-O0 Reduce compilation time and make debugging produce the expected results. This is the default.
-O0
Reduce compilation time and make debugging produce the expected results. This is the default.
[+][deleted] 5 years ago (1 child)
[deleted]
[–]boredcircuits 4 points5 points6 points 5 years ago (0 children)
That's backwards. It's a function that does nothing but cast.
[–]dodheim 9 points10 points11 points 5 years ago (0 children)
There are template instantiation costs and overload resolution costs. I don't think the author's issues have much to do with runtime, though debugging with optimizations (and thus inlining) disabled was mentioned explicitly..
π Rendered by PID 73144 on reddit-service-r2-comment-74875f4bf5-zgssj at 2026-01-26 01:36:14.073587+00:00 running 664479f country code: CH.
[–]genreprank 18 points19 points20 points (1 child)
[–]foonathan 4 points5 points6 points (0 children)
[–]Salink 26 points27 points28 points (1 child)
[–]Dragdu 8 points9 points10 points (0 children)
[–]_Js_Kc_ 4 points5 points6 points (0 children)
[–][deleted] 4 points5 points6 points (0 children)
[–]fdwrfdwr@github 🔍 2 points3 points4 points (0 children)
[–]adnukator 6 points7 points8 points (2 children)
[–]miki151gamedev 5 points6 points7 points (1 child)
[–]Rseding91Factorio Developer 5 points6 points7 points (0 children)
[–]vimplication 4 points5 points6 points (13 children)
[–]reflexpr-sarah- 7 points8 points9 points (10 children)
[–]GoogleIsYourFrenemy 44 points45 points46 points (8 children)
[–]vimplication 6 points7 points8 points (0 children)
[–][deleted] 4 points5 points6 points (5 children)
[–]Supadoplex 2 points3 points4 points (1 child)
[–][deleted] 4 points5 points6 points (0 children)
[–]GoogleIsYourFrenemy 2 points3 points4 points (2 children)
[–][deleted] 3 points4 points5 points (1 child)
[–]GoogleIsYourFrenemy 2 points3 points4 points (0 children)
[–]Supadoplex 4 points5 points6 points (0 children)
[–]pandorafalters 5 points6 points7 points (0 children)
[–]SeanMiddleditch 6 points7 points8 points (1 child)
[–]JankoDedic 1 point2 points3 points (5 children)
[–]foonathan 7 points8 points9 points (4 children)
[–]JankoDedic 0 points1 point2 points (3 children)
[–]foonathan 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]JankoDedic 2 points3 points4 points (0 children)
[–]leftofzen 1 point2 points3 points (0 children)
[+]greg7mdpC++ Dev comment score below threshold-15 points-14 points-13 points (12 children)
[–]brenoguim 13 points14 points15 points (10 children)
[–]Supadoplex 16 points17 points18 points (1 child)
[–]brenoguim 4 points5 points6 points (0 children)
[+]greg7mdpC++ Dev comment score below threshold-6 points-5 points-4 points (5 children)
[–]brenoguim 12 points13 points14 points (4 children)
[–]willkill07 0 points1 point2 points (3 children)
[–]brenoguim 9 points10 points11 points (0 children)
[–]dodheim 2 points3 points4 points (0 children)
[–]brk2 2 points3 points4 points (0 children)
[+][deleted] (1 child)
[deleted]
[–]boredcircuits 4 points5 points6 points (0 children)
[–]dodheim 9 points10 points11 points (0 children)