What is This doing A Function With a defined function inside it.

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

Hey all.

While googling I found some code like this.

void SomeFunction()

{

auto check = [&](int v1, int v2)-> int

{

//do stuff say add the 2 values

return v1 + v2;

};

//used say in a ???

int rt = check(34, 8);

}

Is this a What??? pointer to a defined function.

and is it wise to do things like this or does it have a impact on code speed or any other overhead.

Because after seeing it I found a place I could use it which would allow me to keep it all in one function.

Any input would be good thank.

What I want to use it for is I have a function FindFreeCell and it has a std::list I use as a ordered list and may addToList could be setout like above.

Advertisement
It's a lambda function. Here you go smile.png -- http://www.cprogramming.com/c++11/c++11-lambda-closures.html

n.b. in C++03, you would implement lambdas/closures manually with this kind of ugly code:

void SomeFunction()
{
	struct { int operator()( int v1, int v2 )
	{
		return v1 + v2;
	};} check;

	int rt = check( 34, 8 );
}

As for performance, the compiler is pretty good at inlining lambdas when appropriate, especially when they don't capture anything...

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

As others have said its a lambda. The example you gave is a bit pointless and does not really show their benefit though.

They really come into their own when closures come into play, this is where they capture values from outside the scope of the lambda. When they do this they can be thought of as a class with one method, the lambda signature, and private data.

The following is C# but much the same

This function when called returns a function that takes void and returns int. The resulting function captures nextId and holds it while something references the returned function.

public Func<int> NextIdFactory()

{

int nextId = 1;

return () => nextId++;

}

Here it is being used. The first call to the factory creates a function that starts at id 1 and increments each call. The second call to the factory created a new version so starts at 1 again

public void DoSomeWork()

{

var getNextId = NextIdFactory();

var idA = getNextId(); // = 1

var idB = getNextId(); // = 2

getNextId = NextIdFactory(); // Reset to new generator
var idC = getNextId(); // = 1

}

You can pass a reference around to the lambda like any other piece of data. They have some powerful uses when you get the hang of them from partial application, caching, memoisation. They are normally associated with a more functional style than OO but are gaining traction in the OO world.

Ok Thanks.

Going by this here.

this is how I had my function before reading here.

.


auto AddToPriorityQueue = [&](std::list<cCell *> &Priorityqueue, cCell *cell )
{}

and after reading I changed it to this

.


cCell *cGridManager::GetNearestFreeCell(D3DXVECTOR3 &startlocation, float mindistance, float maxdistance)
{
	std::list<cCell *> Priorityqueue;//ordered list

	
	//define a function for adding to the above list
    auto AddToPriorityQueue = [&Priorityqueue, &mindistance]( cCell *cell )
    { 
		//if empty list 
		if(Priorityqueue.empty())
		{
			Priorityqueue.push_back(cell);
			return;//done
		}


		std::list<cCell *>::iterator it;
		for(it = Priorityqueue.begin(); it == Priorityqueue.end(); it++)
		{
			cCell *currentcell = (*it);
		
			D3DXVECTOR3 target = cell->Centre - currentcell->Centre;

			float distance = D3DXVec3Length(&target);
			if(distance > mindistance)
			{
				//incert here
				Priorityqueue.insert(it,cell);
				return;//done
			}

		}//end all list Items
		
		//if we get here just add it to the end
		Priorityqueue.push_back(cell);

	};//end AddToPriorityQueue


this is the important parts.

auto AddToPriorityQueue = [&](std::list<cCell *> &Priorityqueue, cCell *cell ) this to

this

auto AddToPriorityQueue = [&Priorityqueue, &mindistance]( cCell *cell )

The later one is the optimum solution, I did also have to do the same with mindistance when I put the queue in the [] the function no longer recognize the variable mindistance.

Is it sharing the queue and recognized vars.

Does it matter which way it goes.

I find them really useful when working with algorithms that take templated callable objects:


struct Person
{
  std::string Name;
  int Age;
}

void OutputCountOfTeens(const std::vector<Person> aInputData)
{
  const auto teenagerCount = std::count_if(aInputData.begin(), aInputData.end(), [] (const Person& aPerson)
    {
      return (aPerson.Age >= 13) && (aPerson.Age <= 19);
    }
  );
  
  std::cout << "We were given " << teenagerCount << " teens.\n";
}
Note that I can define the predicate in-line with the function call without having to make a whole functor class or separate function if I only need it one place, which kind of lets me treat several algorithms as fancy for loops.

This topic is closed to new replies.

Advertisement