Greetings to the community!
I came across the opportunity to do something in C ++ that resembles the declaration of functions inside functions. It looks like this:
#include <iostream> int main() { inline_function(std::string s) { std::cout << "Hello, " << s << "!\n"; } with_name(make_hello); make_hello("Vasiliy Pupkin!"); return 0; }
')
In the example above, a nested “method” is made inside the main method with the name make_hello and then called with the “Vasiliy Pupkin” parameter. Of course,
Hello, Vasiliy Pupkin!
will be displayed on the screen
Hello, Vasiliy Pupkin!
.
Unfortunately, I didn’t manage to drag the name up.
This is done, of course, on macros.
Examples of the same without macros
In C ++, there are still
no nested functions, so we will have to emulate their syntax with something else. Therefore, let us ask another question: what exactly looks like the function, but not the function?
There are two answers: first, a call to the class constructor without creating an object “into emptiness”:
#include <stdio.h> int main() { // class inline_function { public: // inline_function() { printf("Hello, hell!\n"); } }; // inline_function(); return 0; }
Unfortunately, there are two significant "but", which do not allow to use this example in practice:
1. We create one new object for each function call, which is not good. Well, how do I cycle for a lot of calls? Overhead can be tolerated on the fact of the declaration of such a thing, but not for use.
2. Visual Studio with compiler optimization enabled will simply cut the creation of inline_function () as useless. The logic of the compiler is clear (nobody will use this created object anyway, so why create it?) But it is dangerous.
However, there is another thing called “redefinition of operators” - and we can redefine double parentheses (by a cleverly redefined operator () is called a “functor”, how):
#include <stdio.h> int main() { // class inline_function_class { public: void operator()() { printf("Hello, world!\n"); } }; // -- ! inline_function_class inline_function; // inline_function(); return 0; }
In this example, almost everything is fine, except that the class can also be made anonymous, so as not to
inline_function_class
name of the form
inline_function_class
#include <stdio.h> int main() { // class { public: void operator()() { printf("Hello, world!\n"); } } inline_function; // // inline_function(); return 0; }
We write macros
So, the goal - in principle - has been achieved: we have a way to isolate a piece of code inside one method so as not to spoil the external visibility zone. But there is one drawback: in all these examples - for my taste - too many letters. Therefore, we divide our code into three parts:
#include <stdio.h> int main() { // /** -- , , : **/ class { public: void operator()(/* */) { /** -- , , **/ printf("Hello, world!\n"); /** -- **/ } } inline_function; // /** =============================== **/ // inline_function(); return 0; }
The first and second parts can be crammed into two macros, giving them some beautiful names. For example,
#define inline_function(params) \ class \ { \ public: void operator() (params)\ {\ #define with_name(value) \ }\ } value; #define with_params(...) __VA_ARGS__
Using these macros, the code of the “nested function” is much simpler in appearance (although it does not look in the C ++ style):
int main() { inline_function(char * name) { printf("Hello, %s!\n",name); } with_name(hello) hello("Pupkin"); }
Unfortunately, everything deteriorates if you try to set not one parameter of the function, but at least two. In this case, the compiler is clicked, they say, in the inline_function macro of the entire ONE parameter and bast. The problem can be solved by using the __VA_ARGS__ macro (which, although not included in the standard, is supported by all actually used compilers).
A little more complicated, but a function with two parameters will still look acceptable:
int main() { inline_function (with_params(int a, int b)) { printf("%d+%d=%d\n",a,b,a+b); } with_name(plus); plus(2,2); }
In conclusion, I note that
these macros do not provide a return value. Of course, it can and very simply "forward up", so I leave it to the readers.
PS In fact, the technique of making nested classes is as old as the world, and I, of course, did not discover anything new. Nevertheless, it seems to me that such an article is useful in an educational sense and has some aesthetic completeness.