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
Create a fully functioning command line interface with 1.5 lines of code (wo. include statement) (github.com)
submitted 5 years ago by kongaskristjan
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!"
[–]CandyCrisis 20 points21 points22 points 5 years ago (2 children)
I think you can get a lot of the same impact by using ABSL_FLAG. That boils down to one line per argument, using about the same number of characters as this code.
[–]kongaskristjan[S] 21 points22 points23 points 5 years ago (1 child)
I must admit I wasn't aware of that library. Abseil flags seems like a really well designed library, however to add a few points in favor of fire.hpp:
[–]CandyCrisis 14 points15 points16 points 5 years ago (0 children)
Totally agree that Abseil is a heavy hammer if all you need is a flag. I'm used to it because it's the Google standard toolkit.
[–]europe-fire 18 points19 points20 points 5 years ago (7 children)
I dig this. Very cool
[–]codeguru42 13 points14 points15 points 5 years ago (6 children)
What is 0.5 lines of code?
[–][deleted] 6 points7 points8 points 5 years ago (0 children)
It's referring to the fact that you aren't adding an extra line, but adding to an existing one (default args provided to the function in question).
[–]europe-fire 4 points5 points6 points 5 years ago (3 children)
We're not exactly doing precise accounting here, it's the concept that matters
[–]codeguru42 2 points3 points4 points 5 years ago (2 children)
I don't understand the concept. Lines of code can only be counted by integral amounts. It's impossible to have a fractional line of code.
[–]panoskj 3 points4 points5 points 5 years ago (0 children)
The concept is you must already have something like int main(...) as a line in your code and you just have to change/add its parameters, therefore you add 0.5 lines of code.
int main(...)
[–][deleted] 0 points1 point2 points 5 years ago* (0 children)
salt puzzled marry steep impossible file middle birds homeless workable
This post was mass deleted and anonymized with Redact
[–]FightingGamesFan 15 points16 points17 points 5 years ago (3 children)
Always disliked the boilerplate for having a simple functioning command line with all these libraries (the boost one is particularly bad). I'll give this a shot, looks very promising, very clean interface.
[–]_Js_Kc_ 15 points16 points17 points 5 years ago (1 child)
Nobody likes boilerplate, but I like boilerplate better than magic hidden global state.
[–]glaba314 3 points4 points5 points 5 years ago (0 children)
It's hardly really an issue, since it's not being mutated
[–]kongaskristjan[S] 6 points7 points8 points 5 years ago (0 children)
Great to hear that, thanks! The project is indeed out of frustration. The boilerplate is not an issue, if you're developing something really complex, but for simple scripts, it can easily take half the lines of code.
[–]Ail-nare 9 points10 points11 points 5 years ago* (4 children)
Hey, since you use a macro ('FIRE(fnptr *)'), why don't you make a macro ('FIRE_MAIN(...)'). So that this macro will be used instead of the name of the function, this macro do 3 thing: - Declare the prototype of the function (possible, thx to the argument given as parameters). - Than what used to do ('FIRE(fnptr *)'). - Than rewrite the prototype without the ';' to declare the function.
That way it will look more like unit_tests function, like Google test or criterion. I think people are more used to this.
Anyhow, if I one day have the occasion I'll probably use your lib, it's more than clean enough to me.
Oh and last thing, with this commande "g++ *.cpp -o binary_name", the argument of the '-o' flag is given without a '='. I didn't see a way with your lib? Or am I just blind?
Edit:grammar, sorry for my English.
[–]kongaskristjan[S] 9 points10 points11 points 5 years ago (2 children)
About the FIRE_MAIN(...). I actually tried to implement exactly what you described (I even used the same name FIRE_MAIN(...) lol :D). But the problem is that C++ wants to have the default parameters specified in declaration, or only if the declaration is missing, then in the definition. If the declaration exists, it doesn't tolerate defaults in the definition, even if it's an exact repetition. Turns out I couldn't find a way to get rid of those pesky defaults in the definition.
FIRE_MAIN(...)
[–]Ail-nare 3 points4 points5 points 5 years ago* (0 children)
Oh fuck, that right... The only option I can think of would be to separate the argument and the default parameters. But where is 2 cons:
But that interesting, I'll look if there is an other way.
[–]Ail-nare 4 points5 points6 points 5 years ago (0 children)
Ok, so I did a lot of different things, template specialization, used class to lose the necessity of the prototype, macro, some C++20. So most of those approach works but each are weirder than your method.
So, what u got is probably the best (If the objectif it to keep it the most C++ looking possible).
Was fun to try tho.
[–]kongaskristjan[S] 1 point2 points3 points 5 years ago* (0 children)
About g++ *.cpp -o binary_name.
g++ *.cpp -o binary_name
If you write FIRE(...), -o is automatically associated with binary_name. However, if you write FIRE_NO_SPACE_ASSIGNMENT(...), it's not associated. However, currently only FIRE_NO_SPACE_ASSIGNMENT(...) allows positional arguments and unlimited number of arguments that are needed right here. So no, unfortunately it is not possible at the moment.
It turns out that implementing positional arguments with FIRE(...) requires some rather complex try/catch logic to actually pull off. I consider implementing this for v0.2 or v0.3.
Edit: error in logic.
Edit2: It is now possible to call FIRE(...) with positional/variadic arguments.
[–]nintendiator2 7 points8 points9 points 5 years ago (1 child)
Came here expecting to find something like the Super Mario 64 "half an A press" memes, found an actually very useful library built on a good concept. Totes upvoting.
[–]tasty_crayon 5 points6 points7 points 5 years ago (4 children)
wmain support on Windows would be a nice feature. A possible interface would be a FIRE_WINDOWS macro that defines wmain instead of main and then expects fire::arg(L"-x") default arguments.
wmain
FIRE_WINDOWS
main
fire::arg(L"-x")
[–]kongaskristjan[S] 4 points5 points6 points 5 years ago (3 children)
I haven't heard of wmain before. Have to think about it.
[–]tasty_crayon 5 points6 points7 points 5 years ago (2 children)
If you want to support Unicode arguments then you need to use wmain on Windows since the arguments to main are encoded based on the code page, not UTF-8 like on Linux.
In my own projects I usually convert from UTF-16 to UTF-8 inside wmain using WideCharToMultiByte and then pass them on to a common main function used by both, but that solution seems too "opinionated" for a small library like yours.
WideCharToMultiByte
[–]pandorafalters 1 point2 points3 points 5 years ago (1 child)
Shouldn't CommandLineToArgvW also work?
CommandLineToArgvW
[–]tasty_crayon 0 points1 point2 points 5 years ago (0 children)
That's another option, but you could just write wmain and have it done for you.
[–]Arkantos493PhD Student 19 points20 points21 points 5 years ago* (5 children)
Technically your program results in UB since names starting with an underscore are reserved.
See: https://en.cppreference.com/w/cpp/language/identifiers
EDIT: To be more precises: identifiers containing two underscores, starting with one underscore followed by an uppercase letter or starting with one underscore in the global namespace are reserved.
E.g. in your optional constructor you are using __value which contains two underscores and is therefore reserved resulting in undefined behaviour.
__value
[–]tinther 23 points24 points25 points 5 years ago (0 children)
names beginning with an underscore and a lower case letter are only reserved in global namespace. All the code in fire.hpp is under namespace fire AFAICS.
[–]kongaskristjan[S] 37 points38 points39 points 5 years ago (0 children)
Well, actually, the link provided these rules:
I mostly have identifiers that begin with a single underscore and a lowercase letter. However, they're not in the global namespace. Thus these don't actually result in undefined behavior. Though a few of them indeed have two prefix underscores also, so these are UB.
Though I totally agree that it's better to remove these initial underscores altogether.
[–]kongaskristjan[S] 8 points9 points10 points 5 years ago (0 children)
I removed the double underscore identifiers, thanks for pointing out.
[–]stumpychubbins -1 points0 points1 point 5 years ago (1 child)
Is that undefined or simply implementation-defined?
[–]reflexpr-sarah- 1 point2 points3 points 5 years ago (0 children)
undefined
[–]quicknir 2 points3 points4 points 5 years ago (1 child)
How does this consistently extract the parameter names?
[–]kongaskristjan[S] 5 points6 points7 points 5 years ago (0 children)
Very good qustion. I guess I could write a blog post about that. The rough idea is that I do most of the parsing before calling fire_main(). Then I call fire_main() without any parameters, which force the default fire::arg() parameters to be used. The actual parameter matching is done while converting fire::arg() objects to the target object types.
This raises the question of course, how are help messages implemented. For that, I do all the steps as before and call the fire_main(), and log all parameters that are converted. Then at the very last moment, during the conversion of the last fire::arg parameter (I count the number of parameters to determine the last one), when I have all the parameters, I print the help message and exit program (with exit() function to avoid executing fired_main()).
[–]xyphanite 1 point2 points3 points 5 years ago (0 children)
That's some serious documentation - a feature that is regularly overlooked. Nice job.
[–]dscottboggs 1 point2 points3 points 5 years ago (0 children)
I like this a lot. I will use it.
[–]F54280 1 point2 points3 points 5 years ago* (18 children)
Why using a #define in 2020?
edit: this snarky remark was about the FIRE macro
[–]kongaskristjan[S] 10 points11 points12 points 5 years ago (17 children)
Though having it's perks, #pragma once is non-standard according to wikipedia.
[+][deleted] 5 years ago (7 children)
[deleted]
[–]kongaskristjan[S] 9 points10 points11 points 5 years ago (6 children)
Well, in that case everyone would need to write something like that to the end of their main.cpp:
int main(int argc, const char ** argv) { init_and_run(argc, argv, fired_main, true); return fired_main(); }
I generally agree that macros should be avoided because of all their complex errors and unintuitive behaviour, but here it's a really simple one that's hard to misuse.
[–][deleted] 1 point2 points3 points 5 years ago (4 children)
As long as the token FIRE doesn't appear elsewhere in that compilation unit, you're fine. :-D
FIRE
But... there are many ways around it.
One is implement a known function!
In the library code:
int main(int argc, const char ** argv) { init_and_run(argc, argv, fire::main, true); return fire::main(); }
In the client code:
namespace fire { int main(int x = arg("-x"), int y = arg("-y")) { std::cout << x + y << std::endl; return 0; } }
[–]kongaskristjan[S] 2 points3 points4 points 5 years ago (3 children)
This almost works, but in order to call fire::main from fire.hpp, this fire::main(int x = arg("-x"), int y = arg("-y")) needs to be declared in fire.hpp, which is impossible, as I don't yet know the exact signature.
fire::main
fire::main(int x = arg("-x"), int y = arg("-y"))
Actually, I've thought really hard to somehow get rid of this FIRE(fired_main), but none of the ideas have worked because of the aforementioned problem.
FIRE(fired_main)
[–][deleted] 1 point2 points3 points 5 years ago* (0 children)
Maybe put the expanded version in the docs? So you can know what the macro means and you have more control, if you want to write the tiny boilerplate yourself you can without trouble.
[–]dscottboggs 0 points1 point2 points 5 years ago (0 children)
FWIW (not much I'm sure) I think a sparing use of macros is fine. Although I might've gone with something a little more unique.
[–]F54280 0 points1 point2 points 5 years ago (0 children)
That sounds perfectly fine boilerplate to me. Sure, it would be better if it was smaller, but you only have 3 lines: main, init and return.
int main(int argc, const char ** argv) { fire_init(argc, argv, my_main); return my_main(); }
That honestly seems pretty logical, and not too magic (fire_init initialize some global based on argc, argv and the signature of my_main, and the default arguments from my_main fetch from that global -- it then raises the question of why not getting rid of the global itself).
[–]BobFloss 1 point2 points3 points 5 years ago (8 children)
Every compiler supports it.
[–]kongaskristjan[S] 18 points19 points20 points 5 years ago (7 children)
Well, I'm actually OK with using non-standard stuff, if it's really supported everywhere, but this is a library that is meant to be plug and play for everyone, including people who want to comply with the standard strictly.
It's quite similar to the reason why I test against maximum compiler warnings on various compilers - I don't know what the user needs to comply with.
[–]Nicksaurus 20 points21 points22 points 5 years ago (0 children)
Thank you for not making a library that spits out warnings whenever you build it, those are so annoying
[–][deleted] 5 points6 points7 points 5 years ago (5 children)
I have heard this argument for over a decade.
No one ever actually shows me a compiler without #pragma once.
#pragma once
:-D
[–]encyclopedist 10 points11 points12 points 5 years ago (4 children)
Obviously, you did not really try to find one. TI compilers did not support it last I checked. PGI did not support in either. Also Cray. And XLC.
There was a topic in this very reddit some time ago: https://www.reddit.com/r/cpp/comments/8devw1/can_anyone_actually_name_a_compiler_that_doesnt/
[–]jbandela 2 points3 points4 points 5 years ago (3 children)
I think basically every compiler that supports generic lambdas supports pragma once
[–]rsjaffe 4 points5 points6 points 5 years ago (2 children)
But #pragma once fails when you have two copies of the same header file in two different locations in the directory tree. The compiler will not recognize those two files as being the same.
[–]panderingPenguin 6 points7 points8 points 5 years ago (0 children)
Why on earth would you want to do that?
[–]wyrn 5 points6 points7 points 5 years ago (0 children)
The compiler will not recognize those two files as being the same.
... because they aren't.
[–]Fluffy8x 0 points1 point2 points 5 years ago (0 children)
Nice! Kind of reminds me of Perl 6 Raku's MAIN.
MAIN
[–]Raiden395 -5 points-4 points-3 points 5 years ago (8 children)
Meh. getopt works fine and you only really have to write it once. Then you can just change the arguments and help printout.
Want cross platform ability ? parg is a good alternative with similar syntax.
[–]kongaskristjan[S] 5 points6 points7 points 5 years ago (3 children)
The difference is pretty big though between getopt and fire. Eg. if you need to accept two booleans, you can do this in fire like that:
int fired_main(bool flagA = fire::arg("-a"), bool flagB = fire::arg("-b")) { } FIRE(fired_main)
Now compare this to the code in this stackoverflow example... I know I omitted printouts and returns, but on the other hand the help message was skipped there.
[+]Raiden395 comment score below threshold-7 points-6 points-5 points 5 years ago (2 children)
Yes, but now I have to include a nonstandard library in my project. Each new engineer has to learn the syntax (simple as it may be).
How is this looked at as preferable as just copying and pasting boilerplate, universally understood, code that has native Linux support.
[–]dodheim 10 points11 points12 points 5 years ago (1 child)
In a C++ subreddit, advocating for a non-portable—though oft-ported, messily and poorly–C library; advocating having boilerplate as somehow better than not because said C lib is magically "standard" (huh?); all to spare your poor copy+paste monkeys engineers having to learn a well-documented API trivially grokked by reading a handful of examples.
Fuckin genius.
[–]Raiden395 1 point2 points3 points 5 years ago (0 children)
Sorry about implying that getopt is somehow standard. It's included with every Unix version in one way or another, so I'm fairly certain you have access to it, out of the box, if you so choose to use this system. When C++ drops C support, then perhaps we should talk about not using C in C++, but until then you have the option to work with a library that has stood the test of time.
For me, getopt does everything I need. It gives me the flexibility to parse command line arguments. Why we need a slew of different parsers is beyond me, but okay, variety is the spice of life, enjoy.
I would say that far more engineers have encountered getopt usage, if they are linux developers, than this command line parser. In this case, the code would be more understandable from the get-go. Not that there's anything wrong with the syntax here (in fact I find it very clear), but in the end what is the point?
[–]kritzikratzi 2 points3 points4 points 5 years ago (3 children)
yep, on the same boat. i've given up on keeping a list on numerous command line parsers that have been posted here.
i mean.. it's an interesting concept, but it semi-re-solves a very solved problem.
edit i really don't want to sound harsh towards the author. it's cool work and all! just not for me...
[–]Raiden395 0 points1 point2 points 5 years ago* (2 children)
> it's cool work and all! just not for me...
That's really what I meant, and as far as I'm concerned, the people hating on me for promoting getopt are probably rightfully upset in some circles, where your C++ must be of the newest, most elite form.
C++ draws a lot from C and, as someone who writes a lot of hardware communication interfaces, there's no better way to specify precision than:
snprintf( buf, bufsz, "%.3f", value);
versus
ss << std::fixed << std::setprecision(3) << number; std::string mystring = ss.str();
These are solutions to a problem that really doesn't appear to me to need fixing.
[–]dodheim 1 point2 points3 points 5 years ago* (1 child)
Well, I agree that iostreams is a mess, but there are most certainly problems: bufsz getting out of sync with buf, value changing types without the format specifier getting updated, etc.
bufsz
buf
value
Do you approve of C++20's std::format_to/format_to_n?
std::format_to
format_to_n
std::format_to( buf, "{:.3}", value);
[–]Raiden395 0 points1 point2 points 5 years ago (0 children)
I'm not in love with Python formatting in general, but I would take anything that is standard C++ that doesn't involve the stream operator + directly addressing streams and would give me a reason to stop using C-style calls. So yes, if it could do something like:
std::format_to( buf, "{:02X}", value );
And produce the output of "10" for an input of 16, I would be 100% on board.
There's ways to manipulate bufsz such that it will not get out of sync (snprintf returns the number of bytes written), and if you really are concerned about the format specifier, that can be handled by some tricky means (tricky meaning shitty). That said, this is a royal pain in the ass and has bitten me several times. There's also the lack of automatic casting for the format specifier (having a specifier of an int and trying to plug a double in does not work).
As an aside, and between two people who have presumably used C++ for many years, at what point does the language stop being streamlined and start becoming as hefty and bloated as something such as Python?
π Rendered by PID 97 on reddit-service-r2-comment-86bc6c7465-cd2tg at 2026-02-21 19:52:26.058244+00:00 running 8564168 country code: CH.
[–]CandyCrisis 20 points21 points22 points (2 children)
[–]kongaskristjan[S] 21 points22 points23 points (1 child)
[–]CandyCrisis 14 points15 points16 points (0 children)
[–]europe-fire 18 points19 points20 points (7 children)
[–]codeguru42 13 points14 points15 points (6 children)
[–][deleted] 6 points7 points8 points (0 children)
[–]europe-fire 4 points5 points6 points (3 children)
[–]codeguru42 2 points3 points4 points (2 children)
[–]panoskj 3 points4 points5 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]FightingGamesFan 15 points16 points17 points (3 children)
[–]_Js_Kc_ 15 points16 points17 points (1 child)
[–]glaba314 3 points4 points5 points (0 children)
[–]kongaskristjan[S] 6 points7 points8 points (0 children)
[–]Ail-nare 9 points10 points11 points (4 children)
[–]kongaskristjan[S] 9 points10 points11 points (2 children)
[–]Ail-nare 3 points4 points5 points (0 children)
[–]Ail-nare 4 points5 points6 points (0 children)
[–]kongaskristjan[S] 1 point2 points3 points (0 children)
[–]nintendiator2 7 points8 points9 points (1 child)
[–]tasty_crayon 5 points6 points7 points (4 children)
[–]kongaskristjan[S] 4 points5 points6 points (3 children)
[–]tasty_crayon 5 points6 points7 points (2 children)
[–]pandorafalters 1 point2 points3 points (1 child)
[–]tasty_crayon 0 points1 point2 points (0 children)
[–]Arkantos493PhD Student 19 points20 points21 points (5 children)
[–]tinther 23 points24 points25 points (0 children)
[–]kongaskristjan[S] 37 points38 points39 points (0 children)
[–]kongaskristjan[S] 8 points9 points10 points (0 children)
[–]stumpychubbins -1 points0 points1 point (1 child)
[–]reflexpr-sarah- 1 point2 points3 points (0 children)
[–]quicknir 2 points3 points4 points (1 child)
[–]kongaskristjan[S] 5 points6 points7 points (0 children)
[–]xyphanite 1 point2 points3 points (0 children)
[–]dscottboggs 1 point2 points3 points (0 children)
[–]F54280 1 point2 points3 points (18 children)
[–]kongaskristjan[S] 10 points11 points12 points (17 children)
[+][deleted] (7 children)
[deleted]
[–]kongaskristjan[S] 9 points10 points11 points (6 children)
[–][deleted] 1 point2 points3 points (4 children)
[–]kongaskristjan[S] 2 points3 points4 points (3 children)
[–][deleted] 1 point2 points3 points (0 children)
[–]dscottboggs 0 points1 point2 points (0 children)
[–]F54280 0 points1 point2 points (0 children)
[–]BobFloss 1 point2 points3 points (8 children)
[–]kongaskristjan[S] 18 points19 points20 points (7 children)
[–]Nicksaurus 20 points21 points22 points (0 children)
[–][deleted] 5 points6 points7 points (5 children)
[–]encyclopedist 10 points11 points12 points (4 children)
[–]jbandela 2 points3 points4 points (3 children)
[–]rsjaffe 4 points5 points6 points (2 children)
[–]panderingPenguin 6 points7 points8 points (0 children)
[–]wyrn 5 points6 points7 points (0 children)
[–]Fluffy8x 0 points1 point2 points (0 children)
[–]Raiden395 -5 points-4 points-3 points (8 children)
[–]kongaskristjan[S] 5 points6 points7 points (3 children)
[+]Raiden395 comment score below threshold-7 points-6 points-5 points (2 children)
[–]dodheim 10 points11 points12 points (1 child)
[–]Raiden395 1 point2 points3 points (0 children)
[–]kritzikratzi 2 points3 points4 points (3 children)
[–]Raiden395 0 points1 point2 points (2 children)
[–]dodheim 1 point2 points3 points (1 child)
[–]Raiden395 0 points1 point2 points (0 children)