[C++11] 람다(Lambda) 표현식

C++11은 람다 표현식 기능을 제공합니다. 람다 표현식은 함수를 미리 정의하지 않고 필요한 시점에서 사용하고 바로 버리는 것으로 생각할 수 있습니다. 람다가 제공되기 이전에 어떤 함수를 사용하고자 했다면, 그 함수를 미리 정의하고 사용하게 됩니다. 사용하고 난 뒤에 그 함수는 계속 존재합니다.아래는 람다 표현식을 이용해 만들어진 함수 예입니다.

#include "stdafx.h"
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    auto func = []() {
        cout << "Hello World" << endl;
    };

    func();

    return 0;
}

8번 코드에서 람다 표현식을 이용해 함수를 정의하고 있습니다. 정의된 함수는 예제처럼 어떤 변수에 함수를 할당해 놓고 12번 코드에서 실행할 수 도 있지만 어떤 변수에 할당하지 않고 바로 실행할 수 도 있습니다. 즉, 아래처럼 말입니다.

#include "stdafx.h"
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    []() {
        cout << "Hello World" << endl;
    }();

    return 0;
}

첫번째 예제와는 다르게 이 두번째 예제는 필요한 시점에 함수를 정의하고 바로 실행하고 함수를 폐기하고 있습니다. 8번 코드에서 보는 것처럼 람다 표현식은 2가지로 구성됩니다. []과 {}이며 []는 람다 소개자(Lambda Introducer) 또는 Capture Clause라고 하며 {}는 람다 몸체(Lambda Body)입니다. 람다 몸체에 함수 구현 코드가 존재하며 람다 소개자에 외부 변수를 어떤 식으로 참조할지에 대한 Capture 지정자과 함수에 입력될 인자(Parameter) 리스트가 지정됩니다. 예를 들어 람다 표현식으로 정의한 함수의 인자로 int를 받아 출력하는 함수는 다음과 같습니다.

#include "stdafx.h"
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    [](int a) {
        cout << a << endl;
    }();

    return 0;
}

이제 람다 함수(람다 표현식으로 정의된 함수)에 대해 몇가지 예를 통해 좀더 정리해 보겠습니다. 다음 코드를 살펴 보겠습니다.

#include "stdafx.h"
#include 
#include 
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    vector v { 1, 2, 3, 4, 5 };

    for_each(v.begin(), v.end(), [](int v) {
        cout << v << endl;
    });

    return 0;
}

위의 코드 중 12번의 for_each 함수는 컨테이너의 각 요소를 인자로 어떤 함수(또는 함수객체)를 호출하는 것으로 for_each의 세번째 인자가 바로 호출되는 함수(또는 함수객체)가 됩니다. 일반적으로 호출할 함수를 미리 정의해 두어야 하나 여기서는 람다 함수를 이용해 미리 함수를 정의하지 않고 필요한 시점에 함수를 정의하고 사용하고 있습니다. 다음 예제를 보겠습니다.

#include "stdafx.h"
#include 
#include 
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    vector v { 1, 2, 3, 4, 5 };

    auto it = find_if(v.begin(), v.end(), [](int v)->bool {
        return (v % 2) == 1;
    });

    cout << *it << endl;

    return 0;
}

위의 코드 중 12번에 있는 find_if 함수는 컨테이너를 구성하는 요소 중 어떤 조건을 만족하는 첫번째 요소의 값을 반환하는 함수인데, 조건을 지정하기 위해 함수 또는 함수 객체를 세번째 인자에 지정됩니다. 여기서는 람다 함수를 통해 조건 함수가 지정되었는데 이 함수의 반환 타입(Type)을 지정하기 위해서 ->bool를 사용함으로써 반환 타입이 bool이라고 명시하고 있습니다. 엄격하게는 이 ->bool 코드를 생략할 수 있는데, 이는 컴파일러가 이 람다함수의 반환타입을 추론할 수 있기 때문입니다. 컴파일러의 추론 대신 직접 반환 타입을 알려주기 위해 ->(type) 연산자를 사용할 수 있다는 것에 대한 예제입니다.

#include "stdafx.h"
#include 
#include 
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    vector v { 1, 2, 3, 4, 5 };
    int sum = 0;

    for_each(v.begin(), v.end(), [&](int v) {
       if (v % 2 == 0) sum += v;
    });
    
    cout << sum << endl;

    return 0;
}

위 코드 중 13번의 람다 함수를 보면 []에 해당하는 람다소개자의 형태가 [&]처럼 되어 있습니다. 이 [&]의 의미는 람다 함수 앞단에 모든(All) 외부 변수를 참조 타입(Reference Type)으로 잡아(Capture) 사용하겠다는 의미입니다. 실제 람다 함수 구현부를 보면 외부에 존재하는 sum 변수를 사용하고 있습니다. 참조 형태로 사용하겠다고 했으므로 람다 함수 내부에서 변수값을 변경하면 외부에서도 변경되는 것을 알 수 있습니다. 람다 소개자가 []일 경우에는 어떤한 외부 변수도 사용하지 않겠다는 의미이며 [&]는 모든 외부 변수를 참조로 사용하겠다는 것이고, [=]는 모든 외부 변수를 상수값(const)으로 값 자체를 복사(Copy)하여 사용하겠다는 의미입니다. [&a]는 외부 변수 중 a만을 참조값으로 사용하겠다는 의미이고 [&a, =b]는 a는 참조값으로 b는 상수값으로 사용하겠다는 의미입니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다