What is the type of a Lambda with capture?

Started by
4 comments, last by MarcusAseth 6 years, 8 months ago

Premise: this question is just out of curiosity, I don't need to use this knowledge, therefore answers like "you don't need to do it" or "just use auto" are invalid. This is for science :D

The code below compile:


#include <iostream>
using namespace std;

int(*myFunction(int b))(int a)
{
	int(*f)(int a) = [](int a) { int myVariable = a ; return ++myVariable; };
	return f;
}

int main()
{
	while (true){
		cout << myFunction(5)(12);
	}
}

Now if I change the lambda to capture b, the code doesn't compile anymore, code below:


int(*myFunction(int b))(int a)
{
	int(*f)(int a) = [b](int a) { int myVariable = a + b; return ++myVariable; };
	return f;
}

so my question is, what does the lambda type being assigned to "f" when I add the capture changes into?

How would you re-write "int(*f)(int a)" such that it compiles when there is that capture of "b"? (no auto, typedef, using or other tricks allowed, I want to see the ugly form :D)

Advertisement

The type is anonymous. Only the compiler knows it, there's no way to determine what it is. A lambda with a capture tends to compile down to something like:


// this
auto f = [a](int x) -> int
{
   return x + a + 2;
};

// turns into this
struct
{
  int a;
  
  int operator()(int x) 
  {
    return x + a + 2;
  }
} f {a};

You can't use a function pointer type to refer to a lambda with a capture. std::function will allow you to do what you're trying to do:


std::function<int(int b)> myFunction(int a)
{
	std::function<int(int b)> = [](int a) { int myVariable = a ; return ++myVariable; };
	return f;
}

Otherwise... Just use auto.

1 minute ago, Oberon_Command said:

Just use auto.

:D

I see, thanks :P

I think you're starting to bump against the reason the standards committee had to accept the updated version of auto.  People had been pushing for it for years, but to get all the lambda functionality in required some unnamable types. The simpler versions generate an anonymous class with a functor, meaning operator(), which gives the result. 

 

Lambdas without a capture can be converted to a function pointer. That is guaranteed in the standard, and easy enough to figure out how to mimic with function objects like @Oberon_Command did above.  The compiler generates them as anonymous objects, but you could do it yourself.

Lambdas with a capture can sometimes be converted, but sometimes not. When you start dealing with captures there are edge cases that I never really understood that made it impossible to think of as a regular function object.  These cannot be generated with an actual type in C++, they are unnameable, so they were called Lambda Closures and can only be referred to with auto.  Their actual type is basically "block of code".

 

Since nobody can actually name what the type is, you've got to use auto.

4 minutes ago, frob said:

Since nobody can actually name what the type is, you've got to use auto.

Which is also less headache, so I don't complain :P

This topic is closed to new replies.

Advertisement