The other day, a C++ student approached me on-line, while he researched some tiny framework of mine. In his own words he”bumped into this problem”. For some reason, he still uses Visual Studio 2017 IDE. Annoyingly he had an image, not a source code, to prove the problem. Sigh.
Student: “Ok here we have two lambdas which are supposed to be the same but are (very slightly) differently declared. But IDE refused to allow me to do static_assert() for comparing them for equality? With errors as on the picture!”
There has to be a Method
Student: “IDE error popup text is obviously not very logical to humans. Is this MSVC error of ISO C++ forbids this!?”
I have not yet met anybody successfully starting a computer programing with C++ as a first language. Thus:
There are no C++ Beginners, there are C++ Students
Meaning: it is humanely impossible, to begin with, C++. If one does try he is in danger to stay a beginner forever. C++ is just one mountain too serious to climb, without a guide. Even with a personal tutor.
And here is me the “guide” telling to this “climber”: “you are not ready yet to start climbing. It is best to play with some modern interpreted language to teach yourself things, which are otherwise just a dry theory difficult to understand. Starting with pure theory. will take months or more, and will be a struggle with unsatisfactory outcome. ”
I suggested him to use JavaScript and one of the good and simple online “schools”. W3C Schools has many opponents me including, But for absolute programming beginners, it is a good playground.
To fortify my claim, we quickly opened “my first” online javascript editor, and typed in this:
1 2 3 4 5 6 |
// this is JavaScript inside an HTML page <script> function function_1() {} function function_2() {} alert ( function_1== function_2); </script> |
The result is, of course, false (in an alert message box). Two functions are two separate objects. They occupy separate memory when compiled and they have different names. One does not need a C++20 compiler to prove that.
Armed with this knowledge we opened Visual Studio 2019 and quickly started a new C++ console project. With one main.cpp
. Then we typed this:
1 2 3 4 5 6 |
// this is C++17 void function_1() {}; void function_2() {}; /* does not compile */ static_assert(function_1== function_2); |
The difference is we now have also proven in (completely) different language two functions are two different objects. Surely more clear and easy to remember.
In theory that is also very clear. The function name is part of the function definition.
sin(x)
There can be only one such function.
calculates_sin(x)
Those are two different functions. Regardless of the fact they are both “doing the same thing”.
But what about lambdas?
Lambdas aka “closures” are how C++ implements nameless functions. They have been implemented in JavaScript from the beginnings, many years ago. In JavaScript, they are called nameless or anonymous functions.
1 2 3 4 5 |
// JavaScript in an HTML page // comparing two pure functions aka lambdas <script> alert ( function () {} == function () {} ); </script> |
And again the result is false. Two functions are two objects. In JavaScript, these nameless functions are the key constructs to create a “closure”.
1 2 3 4 5 6 7 |
// JavaScript closure <script> (function ( arg ) { alert( arg.title ) ; } ( window )) ; // call it with argument </script> |
Far from the cushy interpreted world of JavaScript and HTML DOM, to arrive at compiled native executable one could do something similar in C++, this way:
1 2 3 4 5 6 7 8 |
#include <Windows.h> auto closure_name = []( auto message ) { MessageBoxA(NULL, message, "Closure", MB_OK); return true; } // call the closure aka lambda // immediately ("Hello Lambda!"); |
The result is amazing:
As ever, please copy-paste the C++ code above, into your Visual Studio 2019 and follow closely through its debugger.
Let us conclude for now, by showing an example of using anonymous closure in C++.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// named closure auto use_anonymous_closure = [] (auto a_closure) { a_closure(); return true; } // begin immediate call ( // anonymous closure [] { MessageBoxA(NULL, "Hello Anonymous Lambda!", "Anonymous Closure", MB_OK); } // end call ); |
Notice how anonymous closure is made as one, and then passed as an argument to use_anonymous_closure
where it is executed.
There are many more details about C++ closures, applicable to different levels of understanding C++. For the brave and curious students here is one practical and very feasible usage example of closures.
Conclusion
This student is a very good engineer. Methodical with the ability to learn. Alas, there was no method in his valiant quest here. Probably VS 2017 IDE has “driven him up the wall” with this, I have to admit rather misleading IDE error message,
I do think I have armed him with the right tool to catch many useful moments of C++ discovery,