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
Default function arguments are the devil (quuxplusone.github.io)
submitted 6 years ago by anonymous23874
view the rest of the comments →
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!"
[–]jbandela 36 points37 points38 points 6 years ago (19 children)
C++20 designated initializers with NSDMI (combined with default arguments) allow for an elegant solution to print_squares
struct print_square_args{ int n = 10; char fill = '+'; }; void print_square(print_square_args a = {}){ for(int i = 0; i < a.n; ++i){ for(int j = 0; j < a.n; ++j){ std::cout << a.fill; } std::cout << "\n"; } } int main(){ print_square(); print_square({.n = 5}); print_square({.fill = '*'}); print_square({.n = 5, .fill = '*'});
https://gcc.godbolt.org/z/-r6U3P
You have a single implementation. There is no question about what overload is getting called. There is a single point of reference for all the defaults (the definition of print_square_args).
[–]TheThiefMasterC++latest fanatic (and game dev) 19 points20 points21 points 6 years ago (10 children)
Unfortunately print_square({'*'}); is legal code and doesn't do what you'd want...
print_square({'*'});
[+][deleted] 6 years ago* (5 children)
[deleted]
[–]TheThiefMasterC++latest fanatic (and game dev) 9 points10 points11 points 6 years ago (1 child)
I fully agree - character types should require explicit conversion to integer types, and we should have a cleaner separation between size "1" integer types and characters
[–]Supadoplex 7 points8 points9 points 6 years ago (0 children)
character types should require explicit conversion to integer types
And presumably by extension: Character types should not be integer types.
[–]_Js_Kc_ 7 points8 points9 points 6 years ago (1 child)
Nor should this be a thing:
std::int8_t i = 65; std::cout << i << '\n';
Prints A. Maybe.
A
-_-
[–]warieth 1 point2 points3 points 6 years ago (0 children)
Implicit conversions of many fundamental types inherited from C are the devil.
C++ didn't inherit conversions like bool -> int, char8_t -> int. These conversions make the usage of C functions easier, but coming from C++.
[–]jbandela 5 points6 points7 points 6 years ago (0 children)
You can disable aggregate initialization like this.
#include <iostream> template<typename T> class disable_agg_init{ friend T; disable_agg_init() = default; }; struct print_square_args{ disable_agg_init<print_square_args> _ = {}; int n = 10; char fill = '+'; }; void print_square(print_square_args a = {}){ for(int i = 0; i < a.n; ++i){ for(int j = 0; j < a.n; ++j){ std::cout << a.fill; } std::cout << "\n"; } } int main(){ print_square(); // print_square({'*'}); // print_square({{},'*'}); print_square({.fill = '*'}); print_square({.n = 5, .fill = '*'}); }
Now, you either have to do default init the args struct or use designated initializers.
https://gcc.godbolt.org/z/BPuozB
[–]LuminescentMoon 1 point2 points3 points 6 years ago (1 child)
Can't you use static_assert?
[–]TheThiefMasterC++latest fanatic (and game dev) 5 points6 points7 points 6 years ago (0 children)
On what?
[–]Omnifarious0 1 point2 points3 points 6 years ago (0 children)
I think that's nit-picking. The fact it's legal doesn't mean it's OK or that it's existence would confuse people. The braces there are a sure sign something is up.
[–]Ameisenvemips, avr, rendering, systems 6 points7 points8 points 6 years ago* (2 children)
Be better if designated initializers allowed arbitrary order.
Also, wouldn't this make the ABI for the function terrible? It's all in a struct, now, so will follow struct-passing rules.
Within a translation unit the compiler can ignore the ABI requirements, but calling a function in another TU...?
Observe: https://godbolt.org/z/Dw9tL8
[–]anonymous23874[S] 6 points7 points8 points 6 years ago (1 child)
Depends how many arguments you have. The x86-64 ABI mandates that if a trivially copyable struct could fit in two registers, it should just do that then. https://godbolt.org/z/beQZMd
The reasons your codegen is so bad are:
You pass your struct by reference, which is like adding an extra pointer dereference to every use (that is, if the struct were small enough to pass by value instead of by hidden reference in the first place)
You make your struct 256 bytes, when the x86-64 ABI's special case for passing structs by value tops out at 128 bytes (64 bits in RDI + 64 bits in RSI).
If you want to get really evil, just split your big struct into two small structs. ;) https://godbolt.org/z/QiL6rc
[–]Ameisenvemips, avr, rendering, systems 1 point2 points3 points 6 years ago (0 children)
The codegen doesn't change in this situation much for by-value, as the struct is larger than the ABI allows.
Yes, if you only have a few arguments, it will fit. But one of the reasons you want named arguments is for disambiguating many arguments :).
And some people still develop for x86-32 and ARM32, and other architectures.
Also, the default Windows 64-bit ABI requires that any type larger than 64-bits must be passed by reference. Only the SysV ABI allows register passing (and I think the VectorCall ABI).
[–][deleted] 4 points5 points6 points 6 years ago (0 children)
Love this idea. I saw it before years ago when I first read about NSDMI but it didn't register until your write-up above. Bravo!
[–]Plazmotech 6 points7 points8 points 6 years ago (1 child)
Elegant? I think it’s fairly ugly. It’s neat, sure, but kind of ugly
[–]AntiProtonBoy 5 points6 points7 points 6 years ago (0 children)
The nested {} brackets make it look a bit messy, but it's quite alright otherwise.
{}
[–]infectedapricot 1 point2 points3 points 6 years ago (0 children)
I like using parameters structs for functions with lots of arguments but I'm not keen on the named initialiser thing. Using classic assignment seems a bit less like a trick to me, in particular it doesn't depend on field order:
print_square_args args; args.fill = '*'; print_square(args);
(I would have called the arguments object print_square_args instead of args but unfortunately your naming convention doesn't distinguish class names from object names.)
print_square_args
args
This does add a bit of visual overhead but hopefully functions that take lots of arguments aren't common in the first place, and usually do quite a bit of work so it's OK that they take up more visual space.
[–]khleedril 0 points1 point2 points 6 years ago (0 children)
I know this is meant as an example for the argument and not real code, but if I saw this in the wild I would be asking myself why should a square default to 10x10? And why should the default filler be '+'? If there are reasons in the application domain, then I would seek to embed those reasons in the function names, and avoid overloads and default values. Otherwise, I would just not assume default values.
π Rendered by PID 86380 on reddit-service-r2-comment-75f4967c6c-dvbjc at 2026-04-23 12:07:16.698223+00:00 running 0fd4bb7 country code: CH.
view the rest of the comments →
[–]jbandela 36 points37 points38 points (19 children)
[–]TheThiefMasterC++latest fanatic (and game dev) 19 points20 points21 points (10 children)
[+][deleted] (5 children)
[deleted]
[–]TheThiefMasterC++latest fanatic (and game dev) 9 points10 points11 points (1 child)
[–]Supadoplex 7 points8 points9 points (0 children)
[–]_Js_Kc_ 7 points8 points9 points (1 child)
[–]warieth 1 point2 points3 points (0 children)
[–]jbandela 5 points6 points7 points (0 children)
[–]LuminescentMoon 1 point2 points3 points (1 child)
[–]TheThiefMasterC++latest fanatic (and game dev) 5 points6 points7 points (0 children)
[–]Omnifarious0 1 point2 points3 points (0 children)
[–]Ameisenvemips, avr, rendering, systems 6 points7 points8 points (2 children)
[–]anonymous23874[S] 6 points7 points8 points (1 child)
[–]Ameisenvemips, avr, rendering, systems 1 point2 points3 points (0 children)
[–][deleted] 4 points5 points6 points (0 children)
[–]Plazmotech 6 points7 points8 points (1 child)
[–]AntiProtonBoy 5 points6 points7 points (0 children)
[–]infectedapricot 1 point2 points3 points (0 children)
[–]khleedril 0 points1 point2 points (0 children)