Hey!
A few months back, I watched my first C++ competitive programming stream (I don't remember the guy who was streaming but he was contesting in one of CodeForces' competitions). It was this problem related to binary trees and optimisation. At that time, I had no idea about a lot of things. He managed to solve it but only after some debugging. Now that I think of the syntax he used while debugging, I'm fascinated but puzzled as well as to how he did it. Okay, so, let me explain more about it and the reason as to "why" it fascinates me.
He wrote the entire code in one go, occasionally compiling to check for syntax errors. When he test ran with actual sample inputs, the result was wrong. So, he started debugging. Not the usual way mere mortals like me would using the rich debugging tools that modern IDEs provide but this way:
Now, look carefully, it's a function called Debug, the left shift operator and then the variable name whose values he wanted to see. This yielded him all the changes to values of "SomeVariable" as output. At that time, I thought of it as some simple operator overloading with some other code in the function definition that tracks all changes in "SomeVariable" and stores it and displays it when asked to. This brings me to my first question.Code:Debug () << SomeVariable;
I learnt operator overloading can be done only for class methods to have the operators behave in a certain way. Can operator overloading also be done for non-member functions?
If not, how can I write such syntax and what kind of code would I be looking at to enable this?
He probably didn't use classes because I never saw him create an instance. He straight out wrote the above code just before the "return 0;" and ran it again and his output was something like:
The "created" and "deleted" basically meant that "int Perks = SomeVariableThatHasValue175" was on line 27 and Perks went out of scope on line 140.Code:. // The solution to the problem followed by: . . [LINE : 27] "Perks" created : 175 [LINE : 29] "Perks" : 200 [LINE : 85] "Perks" : 225 (loop iteration 1) [LINE : 85] "Perks" : 250 (loop iteration 2) [LINE : 85] "Perks" : 275 (loop iteration 3) [LINE : 85] "Perks" : 300 (loop iteration 4) [LINE : 85] "Perks" : 400 (loop iteration 12) [LINE : 99] "Perks" : 400 (std::cout) [LINE : 140] "Perks" deleted : 400
I found this tool, which he mentioned that he programmed himself while he was typing the syntax for its usage, very fascinating. So, I want to, at the least, understand how to use such syntax manipulation. Obviously, I could just do "Debug (SomeVariable)" syntax but in the end, I still wanna know how, what he did, was made possible.
Now, my second question.
I understand how he got the line numbers and stuff printed by using the __LINE__ , etc. What I have a hard time wrapping my head around is how did he get Debug () to store all the changes to SomeVariable. That line of code is just before the "return 0;" statement so the debug code doesn't have any idea about what happens to SomeVariable before it is called. So, there must be a background thread running which records changes in variable values into a vector, let's say.
If I get a basic understanding of this, I can, probably, proceed and write code for a simple and similar tool. I've had experience writing other Debug macros and Logging tools but this was just insane when I started thinking hard about it, which was today.
Thanks for the help!