C++ Lambda

What is Lambda?

Posted by dydtjr1128 on June 06, 2019 · 10 mins read CPP
Lambda

1. Intro

lambda는 C++11부터 지원이 되었으며 Functor나 for-each를 이용한 반복등을 이용한 함수를 깔끔하고 쉽게 만들기 위한것이다.

2. 펑터(Functor)

Functor는 함수처럼 동작하는 클래스를 의미하며 ‘함수 오브젝트(Funtion Object)’라고도 불린다. 즉 operator()를 정의하고 이를 이용해서 표현되어있다.

class FunctorClass
{
public:
    return-type operator () ( parameters... )
    {
        // do something...
    }
};

2.1 Functor example

#include <iostream>
using namespace std;

class Point
{
    int xpos, ypos;
public :
    Point(int x = 0, int y = 0) : xpos(x), ypos(y) {}
    Point operator+(const Point &pos) const
    {
        return Point(xpos + pos.xpos, ypos + pos.ypos);
    }
    friend ostream& operator<<(ostream &os, const Point &pos);
};
class Adder
{
public :
    Point operator()(const Point &pos1, const Point &pos2)
    {
        return pos1 + pos2;
    }
};
ostream& operator<<(ostream &os, const Point &pos)
{
    os << '[' << pos.xpos << ", " << pos.ypos << ']' << endl;
    return os;
}
int main(){
    Adder adder;
    cout << adder(Point(5, 4), Point(6, 10));

    return 0;
}

위의 예제처럼 Functor는 함수 또는 객체의 동작방식에 유연함을 제공할 때 주로 사용된다.

3. Lambda

lambda

위의 사진처럼 람다는

[변수 캡쳐](받을 인자)->리턴타입{함수}(넘길 인자)

의 형태를 띄고 있다.

int main(){
    int a = 10;
    int b = 20;
    int c = 30;
    int result = [](int a, int b)->int {return a + b; }(a, b);
    int result2 = [=]()->int {return a + b; }();
    int result3 = [=,&a,&b]()->int {return a + b+c; }();
    auto result4 = [](int d)->decltype(auto) {return d * 30; }(a);// a를 대입해서 나온결과값이 result4
    int result5 = [a, &b]()->int {return a + b;}();
    auto result6 = [](int d)->decltype(auto) {return d * 30; };//result6는 함수 포인터

    [&b](){ b *= 6; }();// =>동일 [](int &v) {v *= 6;}(b);
    //[b]() {b *= 6; }();//err! 참조가 아닌 값으로 가져와 *만 할 수 없음

    std::cout << "result  : " << result << std::endl;
    std::cout << "result2 : " << result2 << std::endl;
    std::cout << "result3 : " << result3 << std::endl;
    std::cout << "result4 : " << result4 << std::endl;
    std::cout << "result5 : " << result5 << std::endl;
    std::cout << "a  : " << a << std::endl;//a : 10
    std::cout << "b  : " << b << std::endl;//b : 120
    std::cout << result6(10) << std::endl;
}

[변수 캡쳐] : 현재 람다 함수에서 사용할 외부의 변수를 의미한다.

  • [] : 아무 변수도 사용하지 않겠다는 의미
  • [=] : 해당 함수에 존재하는 모든 변수를 값으로 가져와 사용 하겠다는 의미
  • [&] : 해당 함수에 존재하는 모든 변수를 레퍼런스로 가져와 사용 하겠다는 의미
  • [&, a, b] : 해당 함수에 존재하는 모든 변수를 레퍼런스로 가져와 사용하고 a,b는 값으로 가져와 사용
  • [=, &a, &b] : 해당 함수에 존재하는 모든 변수를 값으로 가져와 사용하고 a,b는 러퍼런스로 가져와 사용
  • [a, &b] : a와 b만 가져와 사용하되 a는 값으로, b는 레퍼런스로 가져와 사용

(받을 인자) : ​부분은 말 그대로 함수에서 받는 인자들이다

void func(int a, int b) 에서 (int a, int b) 부분이다. 받을 인자가 없다면 ()로 두면 된다.

->리턴타입 : void, int 와 같이 함수의 리턴형을 명시하는 부분이다.

void라면 ->와 함깨 생략 가능하다. delctype(auto)와 같이 타입 추론형식도 사용가능하다.

{함수} : 함수의 몸체 영역으로 만들고자 하는 코드의 구현부분이 들어가는부분이다.

(넘길 인자) : 호출하는 함수에서 넘겨주는 값들이다 func(3,5); 에서 3,5를 넘겨주는것과 같다.

3.1 Lambda 함수 중복

int a = 10, b = 20;
int result = [&]()->int{
    return [&]()->int{ return a+b;}();
}();

람다 함수 내부에 또다른 람다 함수를 중복 시킬 수 있다.

3.2 클래스 내부의 Lambda 함수

class Adder {
private:
    int a;
public:
    Adder(int a) {
        this->a = a;
    }
    int addNum(int num) {
        return [=]()->int { return a + num; }();
    }
    int addNum2(int num) {
        return [&]()->int { return a + num; }();
    }
};

클래스 내부에서도 람다 함수를 이용한 함수를 구현 할 수 있다.

3.3 Lambda 함수 포인터

auto myFunction = []{std::cout << "This is my function"<< std::endl;};
myFunction();

위의 코드처럼 myFunction가 함수포인터의 형태로 람다 표현식을 가질 수 있음을 확인가능하다.

3.4 Lambda mutable

int i=10;
auto myFunc = [=]()mutable ->int {
    i*=5;
    return i;
};
std::cout << myFunc() << " " << i << std::endl;

i값을 람다 함수 내에서만 변경하고 싶은경우 리턴타입 전에 mutable키워드를 사용하면 내부에서만 변경값이 적용된다. 참조가 아닌 값복사를 이용한 변수 변경을 위해서는 mutable을 붙여주어야 하는 것이다.

위의 코드를 실행하면 결과값으로 50 10이 출력된다.

References

https://docs.microsoft.com/ko-kr/cpp/cpp/examples-of-lambda-expressions?view=vs-2019
https://modoocode.com/196