Type of lambda function using auto

I am trying to write a C ++ lambda function and do not like to use auto as a type. Currently it looks like this:

 #include <iostream> int main() { // Sends the address of an integer to a function which prints out the contents; auto print_int = [](int* a) {std::cout << *a << std::endl;}; int a; a = 3; print_int(&a); return 0; } 

However, I would like to change auto to something like std::function<void(int)> , but I don't know how to do it. Answers to

It seems relevant, but I'm not sure how to adapt it. Thanks.

+6
source share
3 answers

Lambdas are for use with auto or as a template parameter. You never know the type of lambda, and you cannot enter it. Each lambda has its own unique type. Even if you knew the type name, their type names usually contain a character that is not allowed for type names.

Why does lambda have its own type? because in fact the compiler creates a class defined this way:

 struct /* unnamed */ { // function body auto operator()(int* a) const { std::cout << *a << std::endl; } } print_int; // <- instance name 

This code is very close to equivalent (I skipped the conversion operator). As you can see, you are already using auto because lambdas prints the return type.

Some will say they use std::function<void(int*)> , but I disagree. std::function is a polymorphic wrapper around any callable. Since lambdas are callable types, they fit into it. In other words, it works like std::any , but with a call statement. This will cause overhead in your application.

So what should you do?

use auto ! auto not bad. In fact, it can even make your code faster and reduce unnecessary typing. If you feel uncomfortable with auto , well, not worth it! auto great, especially if you have no choice;)

In fact, you can avoid using auto with the template parameter:

 template<typename F, typename Arg> void parametric_print(F function, Arg&& arg) { function(std::forward<Arg>(arg)); } 

Then use it as follows:

 int main() { int a = 3; parametric_print([](int* a) {std::cout << *a << std::endl;}, &a); } 

There you go, no auto ! However, the template parameter is displayed with the same rule as auto . In fact, if the concept is accepted as standard, you can write the same function template as this:

 // maybe C++20 void parametric_print(auto function, auto&& arg) { function(std::forward<decltype(arg)>(arg)); } 

As Oktalist is mentioned, if concepts are accepted as standard, you can replace auto with Callable :

 Callable print_int = [](int* a) { std::cout << *a << std::endl; }; 

But this does not lead to another type, it just applies some rules when deriving a type.

+5
source

Here you go:

 int a; [](int* a) {std::cout << *a << std::endl;}(&a); 

No auto .


However, I would like to change auto to something like std::function<void(int)> , but I'm not sure how to do this.

It is certainly possible. std::functional has a boilerplate conversion constructor. You just pass the lambda to the constructor and all that is. In addition, you will need to correct the type of the argument, since your lambda expects int* , not int (this is a bug that auto fixes).

 std::function<void(int*)> print_int = [](int* a) {std::cout << *a << std::endl;}; 

Please note that there are two drawbacks.

  • std::function wrapper is an indirect layer that hides the actual type of the called object. This wrapper layer adds overhead at runtime and prevents some optimizations.
  • You need to manually update the type if you make changes to the return value or lambda arguments.
+2
source

Lambda has its own unnamed type.

Your translation can be converted to std::function<void(int*)>
(or for the carefree lambda before void (*)(int*) ).

You can create your functor explicitly so that you give it a name, something like:

 class Print_int { public: void operator()(int* a) const {std::cout << *a << std::endl;} }; 

and then

 Print_int print_int; 
+1
source

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


All Articles