반응형

Intro


오늘은 STL 람다에 대해 알아보도록 하겠습니다. 람다는 저도 써본 적이 없고 솔직히 회사 생활하면서 누가 구현한 걸 본 적도 없었습니다.. 그냥 어떤 거구나 정도만 알고 있었던 기능입니다.

실제로 써본적은 없지만 이번에 공부하며 잘만 활용한다면 괜찮은 기능 이 될 것 같습니다(과연... 잘 활용할 수 있는지 의문입니다).

그럼 STL 람다에 대해 자세히 알아 보도록 하겠습니다.

람다(lamda)


람다는 람다 함수 또는 이름 없는 함수라고 불립니다. 그 성질은 함수 객체와 비슷하다고 생각하시면 될 것 같습니다.

람다의 장점

  1. find_if, sort 등의 알고리즘을 사용할 때 특정 조건자를 사용하려면 함수 객체를 선언해야 하는데 람다를 사용하면 객체를 선언할 필요가 없다.
  2. 코드의 길이가 줄어든다.(객체를 선언할 필요가 없기 때문에 코드의 길이가 줄어든다.)

단점

  1. decltype와 sizeof에서 사용이 불가능하다.

람다의 기본 구조

 #include<iostream>
int main(void)
{
    []//  람다 캡쳐
    ()//  함수의 인수 정의
    {}//  함수의 본체
    ();// 함수의 호출
    return 0;
}

Example


지난 시간에 스터디한 auto를 활용하여 람다 변수를 대입할 수 있습니다.auto가 편하긴 편하네요...

 #include<iostream>
int main(void)
{

    auto func = []() {std::cout << "anabebe" << std::endl;};
    func();
    return 0;
}

결과

일반 함수처럼 파라미터도 넘길 수 있습니다.
Example Code

#include<iostream>
int main(void)
{
    auto func = [](int Num) {std::cout << Num << std::endl;};
    func(99);
    func(999);
    func(9999);
    return 0;
}

결과

람다는 변환값(return)을 넘길 수도 있는데, 변환 값(return)의 형은 명시적으로 지정할 수도 있고 암묵적으로 추론이 가능합니다. 그냥 함수처럼 반환 값을 넘기는데 형을 이건 float로 반환해라, 이건 int로 반환해라 할 수도 있고 값을 넘기면 알아서 추론이 가능하게 암묵적으로 추론도 가능하다는 뜻입니다.
Example Code

#include<iostream>
int main(void)
{
    auto func1 = []() {return 3.14;};
    auto func2 = [](float f) {return f;};
    auto func3 = []()->float {return 3.14;};

    float f1 = func1();
    float f2 = func2(3.14f);
    float f3 = func3();
    return 0;
}

람다 캡처
람다를 사용할 때 외부에 정의되어 있는 변수를 내부로 사용하고 싶을 면 그 변수를 캡처하면 됩니다. 캡처는 참조나 복사로 전달이 가능하고, 참조할 때는 &를, 복사로 전달할 때는 그냥 변수 이름을 대입하면 됩니다.

보통 C++에서 사용할 때 Call by Value & Call by Reference를 생각하시면 될 것 같습니다. 흠.. STL을 공부하시면 개념은 알 거라고 생각하고.. 넘어가도록 하겠습니다.

Example Code

#include <iostream>
#include <vector>
#include <algorithm>
int main(void)
{
    std::vector<int>Num;
    int nSum = 0;
    for (int i = 1;i <= 10;i++)
        Num.push_back(i);

    std::for_each(Num.begin(), Num.end(), [&nSum](int sum) {nSum += sum;});
    std::cout << "Sum = " << nSum << std::endl;

    return 0;
}


vector Num에 1~10까지의 숫자를 넣고 for_each함수에 람다 함수를 넣고 캡처 기능을 써서 nSum에 vector값을 더해 줬습니다. 만약 &nSum을 그냥 nSum으로 복사로 캡쳐를 하게 되면 컴파일 에러가 납니다. 이 때 std::for_each(Num.begin(), Num.end(), [=](int sum)mutable {nSum += sum;}); mutable를 추가 하게 된다면 컴파일 에러 없이 사용이 가능합니다. 하지만 복사로 캡쳐를 했기 때문에 람다 내부에서 변경한 외부 변수의 값은 람다를 벗어나면 원래 값인 0으로 출력이 됩니다.

std::for_each(Iterator first, IIterator last, Function fn);
first부터 last전까지 원소들의 각각에 대해 fn을 실행합니다.

Default 캡쳐
람다는 외부의 모든 변수를 참조로 캡처하고 일부는 복사 또는 참조로 캡처가 가능합니다.

int n1, n2, n3, n4, n5;
[&, n1, n2] {};//n3,n4,n5는 참조, n1,n2는 복사
[=, &n1, &n2] {};//n3,n4,n5는 복사, n1,n2는 참조

예를 들어 람다를 [&, n1, n2] {};으로 선언을 했을 때 n1와 n2는 복사로 캡처를 하고, 맨 앞에 &을 선언함으로 나머지 n3,n4,n5는 참조로 캡쳐를 한다는 의미입니다. 반대로 [=, &n1, &n2] {};했을 때 n1과 n2는 참조로 캡쳐를 하고, =을 선언함으로 나머지 n3,n4,n5는 복사로 캡쳐를 한다는 의미입니다.

마무리


람다는 공부하며 느낀 람다의 가장 큰 장점은 STL 중에 find_if나 sort, 그리고 아까 사용했던 for_each 등 알고리즘을 사용할 때
특정 조건자를 사용하려면 함수 객체를 따로 정의해야 했는데, 람다를 사용하니 그 부분이 줄어들었습니다. 확실히 코드의 길이는 줄어듭니다. 하지만 아직 숙련이 부족해서 그런지 익숙하지 않네요....  분명 잘 활용하면... 좋을 것 같긴한데...

이상으로 포스팅을 마치겠습니다. 감사합니다.

반응형

'[C++ STL]' 카테고리의 다른 글

[C++ STL - forward_list]  (0) 2021.06.24
[STL - 메모리 관리(스마트 포인터 shared_ptr, unique_ptr]  (0) 2021.06.08
[C++ STL - tuple]  (0) 2021.05.21
[C++ STL - range based for]  (0) 2021.05.13
[C++ STL - auto]  (0) 2021.04.28

+ Recent posts