안녕하세요. 명월입니다.
이 글은 C++에서 람다식(functional) 사용법과 클로저(closure) 그리고 auto 자료형에 대한 글입니다.
사실 제가 10년전에 C++를 사용할 때는 람다식이 없었습니다. 아니면 있었는데 제가 사용법을 몰랐거나 잘 사용하던 시절이 아니었습니다.
그러다 제가 주력 프로젝트가 웹 프로젝트 비중이 많아지고, 그러면서 Javascript를 배우면서 함수 지향 프로그래밍의 매력을 느끼고 Java와 C#의 람다식을 익히게 되었습니다.
최근, 블로그 글을 작성하면서 예전에 자주 사용했던 언어 C++를 더 잊어버리기 전에 한번 정리해야겠다 생각하고 글을 작성하고 있습니다. 그러던 중 C++도 람다식이 있지 않을까 하고 조사하던 중 역시 C++도 람다식이 있었습니다.
링크 - https://en.cppreference.com/w/cpp/language/lambda
그것도 C++ 11부터 지원을 했네요...(C++ 11이면 10년 전인데....)
테스트 해보니 역시 C++에서도 람다식은 꽤 심플하고 이해만 잘되면 C++ 개발이 많이 편해질 것 같습니다. 참고로 람다식은 디자인 패턴의 옵서버 패턴과 관계가 있습니다.
링크 - [Design pattern] 옵서버 패턴 (Observer pattern)
#include <stdio.h>
#include <iostream>
using namespace std;
// 실행 함수
int main()
{
// 람다식은 []로 시작해서 람다식에 들어갈 파라미터 설정 그리고 화살표, 리턴 데이터 타입 설정한다.
// stack 영역은 람다의 실행 영역이다.
auto lambda = [](int a, int b) -> int { return a + b; };
// 콘솔 출력
cout << " 1 + 2 = " << lambda(1, 2) << endl;
return 0;
}
C#에서는 Action이나 Func 함수가 있지만, C++에는 없습니다. 대신 auto가 있습니다. 이 auto함수는 타입 추론 방식입니다. C#에서는 var타입과 같습니다.
(void*)와는 조금 타입의 차이가 있습니다. void*는 할당된 객체의 메모리 주소라면 auto는 타입의 추론입니다.
즉, int형이 될 수도 있고, float가 될 수도 있습니다. 대신 한 번 추론이 된 타입은 변경이 되지 않습니다.
람다식은 사실 데이터 타입이 조금 복잡합니다.
그래서 변수로 선언할 때는 auto로 선언합니다. 즉, 람다식과 auto 타입은 같이 붙어다니는 타입입니다.
람다식을 위처럼 사용하지는 않습니다. 저렇게 쓸 바에야 함수를 만드는게 낫습니다.
옵서버 패턴을 위한 것입니다.
#include <stdio.h>
#include <iostream>
using namespace std;
// 옵서버 패턴의 함수 (람다식의 설정에 따라 결과값이 바뀐다.)
// 데이터 타입은 return 값이 int형이고 파라미터는 int, int가 있는 람다식이다.
void print(int (*param)(int, int))
{
// 콘솔 출력
cout << " param(1 , 2) = " << param(1, 2) << endl;
}
// 실행함수
int main()
{
// print 함수에 a + b의 람다식을 넘긴다.
print([](int a, int b) -> int { return a + b; });
// print 함수에 a - b의 람다식을 넘긴다.
print([](int a, int b) -> int { return a - b; });
return 0;
}
여기서 람다식을 함수의 파라미터로 받을 때는 함수 포인터로 람다식을 받습니다. auto는 함수에서 파라미터의 자료형으로 사용할 수 없기 때문입니다.
람다식이 나왔으니 클로저(closer)의 개념을 설명하겠습니다.
클로저는 사실 람다 함수의 밖에서 선언된 변수를 사용하는 기능이 클로저입니다.
#include <stdio.h>
#include <iostream>
// 람다식을 위한 해더 선언
#include <functional>
using namespace std;
// 위에서는 함수 포인터를 사용했지만, functional를 이용하면 더 쉽게 람다식을 파라미터로 받을 수 있다.
// 리턴값(파라미터)
void print(function<int(int)> param)
{
// 콘솔 출력
cout << " param(1 , 2) = " << param(1) << endl;
}
// 실행 함수
int main()
{
// 변수 선언
int test = 10;
// 클로져를 사용하기 위한 방법
// &는 참조 방식으로 람다식 안에서 외부 변수의 값을 취득, 수정할 수 있다.
print([&](int a) -> int { return test + a; });
// =는 캡쳐 방식으로 람다식 안에서 외부 변수의 값을 취득은 가능하나 수정은 불가능하다.
print([=](int a) -> int { return test - a; });
return 0;
}
위에서 클로저를 [=]와 [&]를 넣어서 사용했습니다.
그러나 사양에 따라서는 전체 변수의 캡쳐가 아닌 특정 값만 클로저 기능을 사용하고 싶을 때도 있습니다.
[test]를 써서 특정 변수 캡쳐나 [&test]를 써서 변수 참조를 사용할 수 있습니다.
여기까지 C++에서 람다식 사용법에 대한 글이었습니다.
궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.
'Study > C , C++ , MFC' 카테고리의 다른 글
[C++] 쓰레드(Thread)를 사용하는 방법 (0) | 2020.04.07 |
---|---|
[C++] IO (fstream)(파일 읽기 쓰기)를 사용하는 방법 (0) | 2020.04.06 |
[C++] 예외처리(try ~ catch, throw) 사용법 (2) | 2020.04.04 |
[C++] 리터럴 문자열(const char*, const wchar_t*)과 typedef, operator의 사용법 (0) | 2020.04.02 |
[C++] namespace와 using 사용법 (1) | 2020.03.20 |
[C++] 접근 제한자, 추상 클래스(순수 가상 메서드), 오버로드(Overloading)와 오버라이딩(Overriding) (0) | 2020.03.20 |
[C++] 클래스 상속 (0) | 2020.03.19 |
[C++] 템플렛(Template) (2) | 2020.03.19 |