람다함수 (= 익명 함수)
: 변수형 함수
#include <functional>
std::function을 사용하기 위한 헤더파일
이 헤더파일을 포함해야 std::function을 사용할 수 있다.
람다를 사용하기 위해 꼭 사용할 필요는 없지만
해두지 않으면 여러모로 문제가 생긴다.
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <functional> int main() { std::function<void()> foo = [=]() { printf("Hello World"); }; // 파란색 부분이 람다 함수 // std::function<void()> foo = 부분은 람다 함수를 받아서 std function으로 변환돼서 변수 형태로 함수가 만들어지게 된 것 foo(); return 0; } |
람다 함수의 구조
[ 캡쳐 ] ( 파라미터 ... ) -> 리턴 { ... }
[ 캡쳐 ] : 람다함수 외부의 값을 캡쳐하는 곳
( 파라미터 ... ) : 람다함수의 파라미터
-> 리턴 : 람다함수의 리턴값을 정의
{ ... } : 함수의 몸통
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <functional> int main() { int myvalue = 100; std::function<void()> foo = [=]() { printf("Hello World %d", myvalue); // 안된다 }; foo(); return 0; } |
람다 함수 바깥에 있는 값을 안쪽에서 쓸 수가 없다.
이것을 가능하게 하는 것이 캡쳐 부분인데
대부분의 경우 [=]을 써서 값으로 캡쳐하게 된다.
[&]는 레퍼런스로 캡쳐하는 경우
대부분의 경우 캡쳐한 순간에 값이 안에서 쓰는 경우가 일반적
std::function<T>
람다함수는 std::function의 변수형에 지정될 수 있다.
이 지정된 변수는 함수의 리턴 타입과 파라미터 타입에 따라 정해지게 되는데
예를 들어 리턴타입이 bool이고 파라미터를 int, float로
두 개를 받는다면 템플릿 타입은 다음과 같다.
std::function<bool (int, float)> someFunction;
std::function<void()> foo = [=]() {
printf("Hello World %d", myvalue);
void() 는 함수 타입을 지정해주는 곳, void면 파라미터가 없는 함수타입
int, float의 경우
std::function<void(int, float)> foo = [=](int value1, float value2) {
이런식으로 파라미터의 값을 받아줘야한다.
보통의 경우 너무 길어지기 때문에
std::function<void(int, float)>을 auto 라는 키워드로 대체한다.
타입이 굉장히 길어질 때 한 번에 만들어서 assign 할거면 auto라는 타입을 사용
auto를 사용하더라도 타입의 원형이 std::funcion인지는 알아야한다.
std::bind
: 함수 그자체를 끌어오는 것
일반적인 함수를 변수형태의 어떤 함수로 만들어 줄 수 있다.
람다함수는 새로운 변수형 함수를 만든다고 한다면
std::bind는 이미 존재하는 함수를 변수 형태로 만들어
std::function 클래스 인스턴스로 만들어준다.
이 std::bind를 활용하면 이미 존재하는 함수를
변수 형태로 취급할 수 있게 된다.
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <functional> #include <string> void foo() { printf("Hello World\n"); } int sum(int value1, int value2) { return value1 + value2; } int main() { std::function<void()> local_foo = std::bind(foo); // 함수형 변수, foo()함수를 가지고 local_foo 변수를 만들었다. // std::function<void()> 대신 auto 사용 가능 local_foo(); auto local_sum = std::bind(sum, std::placeholders::_1, std::placeholders::_2); // sum 함수에 파라미터가 있기 때문에 std::placeholders::_1, std::placeholders::_2 써준다. int result = local_sum(10, 20); printf("result: %d\n", result); return 0; } |
std::bind는 클래스 내부에 있는 함수를 바인딩하기 위해서는 몇 가지 절차가 필요하다.
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <functional> #include <string> class Marine{ public: void attackTo(const char* target) { printf("마린은 %s를 공격했다.\n", target); } }; int main() { Marine* m = new Marine(); // 클래스 Marine에 있는 attackTo를 바인딩 하고 싶은 경우 auto attack = std::bind(&Marine::attackTo, m, std::placeholders::_1); attack("히드라"); // attack이라는 함수는 자동적으로 Marine* m의 m이 이 클래스 인스턴스의 attackTo라는 함수를 히드라 라는 파라미터를 갖고 실행하게 된다. return 0; } |
std::bind를 쓰는 경우
대부분의 경우에 Callback 함수에서 이용이 된다.
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <functional> #include <string> int main() { int some_value = 50; auto foo = [=](int a, int b) ->int { printf("Hello World %d\n", some_value); return a + b; }; // 함수인데도 {}안에서 마치 변수처럼 선언이 되기 때문에 ; 붙이기 int value1 = 100; int value2 = 200; int result = foo(100, 200); printf("%d", result); return 0; } // 위에서 아래로 실행되는 구조이기 때문에 some_value가 나타나지 않는 시점에 선언하게 되면 some_value를 캡처할 수 없어 오류 캡처되는 안쪽의 값은 항상 선언되는 것 보다 위쪽에 있어야한다. |
'C++' 카테고리의 다른 글
c++ 16 ( 파일 입출력 2 ) (0) | 2022.02.25 |
---|---|
c++ 16 ( 파일 입출력 1 ) (0) | 2022.02.23 |
c++ 15 ( 기본 자료구조 - STL 기초 자료구조 활용 ) (0) | 2022.02.23 |
c++ 14 ( Generic 이라고도 불릴 수 있는 개념 ) (0) | 2022.02.22 |
c++ 13 ( const / static / extern ) (0) | 2022.02.19 |