본문 바로가기
Programming/C C++

Lambda를 써야하는 이유와 사용 방법

by Eisen Sophie 2020. 10. 16.

Lambda 람다 - 이름이 없는 함수

 

람다를 써야하는 대표적인 이유는

 

재사용이 되지 않을 어떤 함수를 작성하기 위함이다.

 

#include <iostream>
#include <array>

using namespace std;

bool DescendingSort(int a, int b)
{
	return a > b;
}

int main(void)
{
	array<int, 3> arr;

	for (int i = 0; i < 3; ++i)
	{
		arr[i] = i + 10;
	}

	sort(arr.begin(), arr.end(), DescendingSort);

	for (int num : arr)
	{
		cout << num << endl;
	}
	system("pause");

	return 0;
}

 

위의 코드에서 DescendingSort가 다시는 사용되지 않을 코드라면, 

 

저것은 오히려 유지보수 측면에서 안좋은 영향을 끼친다.

 

그렇기에 람다를 써서 아래와 같이 작성을 해준다.

 

#include <iostream>
#include <array>

using namespace std;

int main(void)
{
	array<int, 3> arr;

	for (int i = 0; i < 3; ++i)
	{
		arr[i] = i + 10;
	}

	sort(arr.begin(), arr.end(), [](int a, int b) {return a > b; });

	for (int num : arr)
	{
		cout << num << endl;
	}
	system("pause");

	return 0;
}

이렇기 작성을 하더라도 같은 결과를 반환한다.

 

람다의 정의는 다음과 같다.

 

[ captures ] ( params ) <specifiers> -> <return_type> { body }

capture는 람다식을 포함하고 있는 범위에 있는 변수를 가져올때 사용한다.

params는 매개변수를 받는 곳이다.

specifiers는 지정자로서 mutable, constexpr, consteval(C++20에서 추가가되었다)라는 키워드들이 있다.

 

 

capture의 종류

 

- = 부모함수에 있는 변수를 전부 값으로 가져온다. 람다식 내부에서 수정할수가 없다.

 

- & 참조로 변수를 가져온다.

 

=캡처 예)

#include <iostream>
#include <array>

using namespace std;

int main(void)
{
	int value1 = 10;
	int value2 = 20;

	auto add = [=]() {return value1 + value2; };

	cout << add() << endl;

	system("pause");

	return 0;
}

=를 사용하여, 부모함수에 있는 변수 value1과 value2를 람다에서 값으로서 사용이 가능하게 됐다.

 

람다함수 내부에서는 value1과 value2의 값을 수정하려고 하면, 에러가 발생한다.

 

&캡처 예)

#include <iostream>
#include <array>

using namespace std;

int main(void)
{
	int value1 = 10;
	int value2 = 20;

	auto add = [&]() {
		value1 = 1000;
		value2 = 2000;

		return value1 + value2; 
	};

	cout << add() << endl;
	cout << value1 << endl;//1000
	cout << value2 << endl;//2000

	system("pause");

	return 0;
}

&를 사용해서 람다함수 내부에서 값을 바꾸었다.

 

 

특정 변수 값들 캡처 예)

#include <iostream>

using namespace std;

int main(void)
{
	int value1 = 10;
	int value2 = 20;

	auto add = [value1, value2]() 
	{
		return value1 + value2; 
	};

	cout << add() << endl;
	cout << value1 << endl;//10
	cout << value2 << endl;//20

	system("pause");

	return 0;
}

 

 

특정 변수들 참조 캡처 예)

#include <iostream>

using namespace std;

int main(void)
{
	int value1 = 10;
	int value2 = 20;

	auto add = [&value1, &value2]() 
	{
		value1 = 1000;
		value2 = 2000;

		return value1 + value2; 
	};

	cout << add() << endl;
	cout << value1 << endl;//1000
	cout << value2 << endl;//2000

	system("pause");

	return 0;
}

 

 

값 캡처와 참조 캡처 예)

#include <iostream>

using namespace std;

int main(void)
{
	int value1 = 10;
	int value2 = 20;
	int value3 = 30;
	int value4 = 40;

	auto add = [=, &value1, &value2]() 
	{
		value1 = 1000;
		value2 = 2000;
		// value3 = 3000; // error
		// value4 = 4000; // error
		
		return value1 + value2 + value3 + value4; 
	};

	cout << add() << endl;
	cout << value1 << endl;//1000
	cout << value2 << endl;//2000
	cout << value3 << endl;//30
	cout << value4 << endl;//40

	system("pause");

	return 0;
}

 

Specifiers 키워드들의 종류와 설명

mutable은 참조가 아닌 값으로 캡처해온 변수들을 람다 내부에서 바꿀수 있게해준다.

constexpr은 함수를 constexpr함수로 만들어 준다. 즉 리턴값을 Compile타임 상수로 만들수 있다.

consteval은 상수를 만들기 위해서 compile타임에 평가를 한다. - 사실 아직 뭔지 잘 모르겠다.