📜 ⬆️ ⬇️

C ++ 0x: Convert a lambda expression to a function pointer

By occupation, I often have to deal with computational problems. They often need to pass a pointer to a function, for example, to plot this function, or to solve an equation. In addition, function pointers are commonly used in various GUI frameworks to indicate which action will be performed when a certain button is clicked.

In the new standard C ++ 0x, zymkania appeared. Without going into details, closures are objects that allow you to create functions directly in the body of other functions. If more - closures allow you to create functional objects - that is, objects for which operator () is defined. On Habré already wrote about them: for example here .

I really liked the innovation and I started to use it. But only bad luck: in meaning, closures and functions are almost the same thing, and to use closures where function pointers should be used cannot be done right away. According to the standard, closures without a capture list should be freely converted into function pointers, but in practice this was not observed, apparently not yet implemented. And I wondered, is it possible to use closures where pointers to functions are used?

Consider an example. Suppose we already have a function printFunctionTable , which allows you to print the table of values ​​of the function, while the argument runs through the values ​​from 1 to 10.
void printFunctionTable(int (*func)(int)){
for(int i=1;i<=10;i++) cout << func(i) << " ";
cout << endl;
}

Of course, we could rewrite this function directly under the closure, and not under function pointers, but such a function can be located in a closed library (as is often the case), so we will look for a way to convert one into another.
')
We also define a function whose values ​​we need to print:
int square(int x){
return x*x;
}

Now we will write the main function, in which we will display a table of squares of functions.
int main(void)
{
printFunctionTable(square);
return 0;
}

Compile and run, we get a label:
1 4 9 16 25 36 49 64 81 100

Now let's try to rotate the same with the closure - the cube of the number.
auto cube=[](int x){
return x*x*x;
}

printFunctionTable(cube);

It does not work - when compiling - an error! Of course - the types are different!
How do we get around this? We will come to the aid of templates.
template <typename CL>
int closureToFunction(int x){
CL cl;
return cl(x);
}

Here we have defined a function template, parameterized by the type CL - that is, the type of our circuit. All we need from our circuit is to call it and return the value.

Now you can use the closure in the place where we used to use the function pointer. It will look like this:

printFunctionTable(closureToFunction<decltype(cube)>);

after compiling and running, we get the following label:
1 8 27 64 125 216 343 512 729 1000

Urrra !!! - works! =)

For reference: decltype is a new keyword in C ++ 0x that allows you to determine the type of the expression, that is, in this case, the type of our cube closure.

That's all - the problem is solved, now we can conveniently define functions for some actions directly along the program text, and not jump back and forth on the source code to put these actions into separate functions.

Additionally, we would like to note that we created only a template for the int (int) signature. As required, you can add other signatures - double (int, double) for example, etc. Also, for convenience, you can make a macro
#define CLOSURE_TO_FUNCTION(cl) closureToFunction<decltype(cl)>

PS It was tested on the Intel C ++ Compiler 11.1 compiler, in theory, it should work in g ++ 4.5 and in visual studio 2010, the main thing is not to forget to put flags when compiling to use c ++ 0x.

Full program code:
#include <iostream>

using namespace std;

void printFunctionTable(int (*func)(int)){
for(int i=1;i<=10;i++) cout << func(i) << " ";
cout << endl;
}

int square(int x){
return x*x;
}

template int closureToFunction(int x){
CL cl;
return cl(x);
}

#define CLOSURE_TO_FUNCTION(cl) closureToFunction <decltype(cl)>

int main(void)
{
printFunctionTable(square);

auto cube=[](int x){return x*x*x;};
auto quad=[](int x){return x*x*x*x;};

printFunctionTable(CLOSURE_TO_FUNCTION(cube));
printFunctionTable(CLOSURE_TO_FUNCTION(quad));

return 0;
}

Source: https://habr.com/ru/post/109226/


All Articles