람다를 알아보기 위해서 아주 알찬 프로그램을 만들어보자. 랜덤 정수 리스트를 작성하고 3, 13으로 나뉘는 게 각각 몇 개 있는지 살펴보자. vector와 STL generate() 알고리즘을 이용해보자.
bool f3(int x) { return x % 3 == 0; }
bool f13(int x) { return x % 13 == 0; }
int main()
{
std::vector<int> numbers(1000);
std::generate(numbers.begin(), numbers.end(), std::rand);
int count3 = std::count_if(numbers.begin(), numbers.end(), f3);
cout << "3으로 나누어지는 매개변수 수: " << count3 << '\n';
int count13 = std::count_if(numbers.begin(), numbers.end(), f13);
cout << "13으로 나누어지는 매개변수 수: " << count13 << "\n\n";
}
실행 결과.
gernerate()의 제1 매개변수, 제2 매개변수는, 다른 많은 STL 알고리즘 함수와 같이 범위를 말한다. 제3 매개변수로는 반환될 값이 들어갔는데 랜덤 수를 반환한다. 그러니까 numbers 벡터에 천 개의 랜덤 수가 들어갔다는 거다. 다음으로 count_if()의 제1 매개변수, 제2 매개변수도 마찬가지로 범위이고, 제3 매개변수는 함수 객체여야 하고 true or false를 반환한다. f3()은 3으로 나누어지는 숫자를 true로 반환하니, numbers 벡터 안에서 3으로 나누어지는 숫자들 개수만 반환해준다. f13()도 마찬가지로 13으로 나누어지는 숫자들 개수만 반환해준다.
다음으로는 펑크터를 이용해보자.
class F_mod
{
private:
int dv;
public:
F_mod(int d = 1)
: dv(d)
{}
bool operator() (int x)
{
return x % dv == 0;
}
};
이런 클래스를 만들어 주었다. 그리고 이를 이용하면 된다.
count3 = std::count_if(numbers.begin(), numbers.end(), F_mod(3));
F_mod(3)은, 멤버 변수가 3으로 초기화된 객체를 생성하고, 함수명만 쓰면 되므로 매개변수가 성립된다.
마지막으로 이 포슨팅의 목적 람다를 알아보자. 람다의 특징은 함수 이름을 생략할 수 있다는 것이다.
[](int x) {return x % 3 == 0;} // 람다 함수.
bool f3(int x) {return x % 3 == 0;} // 일반 함수.
람다 함수는 함수 이름이 [ ]로 되었고, 반환 타입도 알 수 없다. 대신 반환 타입은 decltype이 반환 값으로부터 추정한 값이 된다. 이 경우에는 bool이 되겠다. 만약 반환 구문이 없다면, void취급 당한다. 람다를 매개변수로 넣어보자.
count3 = std::count_if(numbers.begin(), numbers,end(), [](int x){return x % 3 == 0;});
오해했는데, 보통 함수 정의처럼 선언할 수 있는 게 아니라, 매개변수에 바로 넣어줘야 하나보다. 람다에서 본문이 단일 구문을 반환하는 구조라면 타입은 자동으로 결정된다. 그렇지 않다면 다음과 같이 새로운 반환 값을 추정하는 문법이 필요하다.
[](double x)->double{int y = x; return x.y;} // 반환 타입 : double형.
근데 이거 왜 필요한 건가? 문법도 어려운데...
람다 함수의 장점은 그 자리에서 바로 함수의 정의를 볼 수 있다는 점이다. 만약 일반 함수라면, 함수 정의를 찾으려면 조금 시간이 걸릴 것이다. (이게 장점이라니) 근데 사실 일반 함수처럼 정의 할 수도 있다.
auto mod3 = [](int x) {return x % 3 == 0; };
일반 함수와 달리 함수 내에도 정의할 수 있기 때문에, 장점을 살려서 사용할 곳 바로 위에 작성하는 게 좋을 것이다.
람다는 또 다른 특징도 가지고 있다. 대괄호 안에 변수 이름을 넣으면 사용 가능하다.
count3 = std::count_if(numbers.begin(), numbers.end(),
[&count13](int x) {count13 += x % 13 == 0; });
// 이렇게 쓰면 코드에서 count13을 참조로 사용할 수 있고, 이는 실제 변수에도 영향을 미친다.