(3) lambda 표현식
기본적인 틀 : [capture](params)->return_type{body}(params)
의미는 [ 이 람다표현식을 포함한 중괄호 내에서 끌어올 변수가 무엇인가요 ]( parameter들의 자료형은 무엇이고 얼마나 더 있나요 )->( 리턴타입은 무엇입니까 ){ capture한 변수를 갖고 무엇을 할 것인가요 }( 실제 파라미터들은 무엇입니까 )라는 의미가 된다. 차근차근 사용해보자.
"Hello lambda"
[](){ cout<<"Hello lambda"<<endl; }();
위에서 볼 수 있듯이 void형일 경우 "->"가 사라진 것을 볼 수 있다.(->를 사용하면 컴파일이 되지 않는다.)
값의 변화
int main(){
int a =1;
......
}
위의 main내부에 a의 값을 1증가 시키는 람다 표현식을 작성해보면
표현식 | 컴파일 결과 | 설명 |
[](){a++;}(); | X | 람다표현식이 a를 알 수 있는 방법이 없다. capture를 통해서 a의 존재를 알아야 하기 때문이다. |
[a](){a++;}(); | X | capture를 통해서 a를 어떻게 한다는 것은 알았는데 이 방법으로는 a는 immutable이 됩니다. |
[&a](){a++;}(); | O | a를 참조하는 것이군요~. 인자로 아무것도 받지 않고 리턴타입은 void 입니다~ |
위의 결과를 통해 capture는 람다 표현식 외부 변수를 받아와서 body에서 써먹는 모양이구나 하는 것을 알 수있다. 그리고 '받아올 때 어떻게 받아올 것인지(복사와 참조)' , '복사해왔으면 그것을 수정할 수 있는지 없는지'를 결정해줘야 하는 것을 알 수있다.
다음 표는 위에서 컴파일 할 수 없었던 경우들을 대상으로 우리의 목표에 맞게 바꾼 표현식이다.
수정후 표현식 |
설명 |
|
[](){a++;}(); |
int a = 1; int main(){ [](){a++;}(); } |
지역변수 int a를 전역변수로 바꿔준다. |
[a](){a++;}(); |
a = [a]()->int{return a+1;}() |
a를 복사해오는 경우 a의 값을 변경해 줄수 없기 때문이다. [a]()mutable{a++;}() 처럼 비록 mutable 지정자를 이용해 a 값을 증가시키더라도 외부 a의 값은 영향이 가지 않는다. |
매번 캡쳐해줘야 해?
int main(){
int a = 0;
int b = 1;
int c = 2;
[&a,&b,&c](){a++;b++;c++;}();
}
위와 같이 a,b,c를 모두 참조하려다 보면 번거러워질 수도 있다. 이 때는 아래와 같이 capture안에 [&]를 써서 lambda 표현식을 포함한 중괄호 내부의 모든 변수를 참조 하도록 할 수 있다. 마찬가지로 모든 변수를 복사하고자 할 때는 [=]를 사용하면 된다.
int main(){
int a = 0;
int b = 1;
int c = 2;
//[&a,&b,&c](){a++;b++;c++;}();
[](){a++;b++;c++;}();
}
Class 안에서 쓸 때는?
Class안에서 lambda표현식을 Class 멤버로 가지려면 어떻게 해야 할까?
"a와 b를 증가시키는 lambda 표현식을 멤버로 가지는 클래스를 작성해보시오"
class Node{
int a;
int b;
Node():a(1),b(2){}
[&a](){a++;}();
[&b](){b++;}();
}
위와 같이 작성하면 클래스에서 람다 함수를 어떻게 호출해야 할까? Node node; node.[&a]..... 이렇게? 당연하게도 위와 같은 표현은 컴파일이 되지 않는다.
class 띠용{
3
};
이렇게 한다고 해서 띠용 클래스가 3을 멤버로 가지는가? 마찬가지로, lambda 표현식의 결과인 함수 객체를 담을 멤버 변수가 클래스에 필요하다.
이를 std::function을 이용하여 수정하면
class Node{
int a;
int b;
Node():a(1),b(2){}
std::function<void()> a_plus_one = [&a](){a++;}; //body 다음에 나오는 ()가 사라졌으니 주의!!
std::function<void()> b_plus_one = [&b](){b++;};
}
class Node{
int a;
int b;
Node():a(1),b(2){}
std::function<void()> a_plus_one = [this](){a++;}; //auto a_plus_one = [this](){a++;}; 역시도 가능하다
std::function<void()> b_plus_one = [this](){b++;};
}
이를 테스트 해보면
정상적으로 동작하는 것을 볼 수 있다. 다음은 함수 포인터, std::function와 함수 객체를 소개하도록 하겠다.
출처: https://tt91.tistory.com/11
https://blog.koriel.kr/modern-cpp-lambdayi-teugjinggwa-sayongbeob/
https://m.blog.naver.com/PostView.nhn?blogId=gamejung13&logNo=220571625118&proxyReferer=https%3A%2F%2Fwww.google.com%2F
'C++' 카테고리의 다른 글
c++] 레퍼런스와 연산자 오버로딩(2) (1) | 2019.03.07 |
---|---|
c++] 레퍼런스와 연산자 오버로딩(1) (0) | 2019.03.06 |