728x90

C++11 버전에 람다 함수라는 표현식이 등장합니다. 이는 여러 예제에서 확인할 수 있는데 Qt를 하신다면 QML Quick Application Project를 생성했을 때 main.cpp에서도 확인할 수 있습니다.

QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, 
    [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }
, Qt::QueuedConnection);

람다 함수는 함수 호출 과정을 생략해 시간을 절약하고 적응하면 코드의 가독성을 높일 수 있는 함수 표현 방식입니다. 람다함수는 함수 이름이 없기 때문에 익명 함수라고도 합니다.

 

람다 함수의 문법은 아래와 같습니다.

먼저 대괄호에 둘러싸인 캡처입니다. 람다 함수에서 사용하고자 하는 외부 변수를 여기에 명시합니다. 함수 내에서 그 변수를 사용하기 위해서입니다.

int main() {
    int nHeight = 170;
    [](int nWeight) { cout << "Height = " << nHeight << "Weight = " << nWeight; } (50);

    return 0;
}

위 코드에서 람다 함수 내부에서 main 안에 있는 Height를 사용할 때 오류가 발생합니다.

이렇게 람다 외부에 있는 값을 사용하기 위해서는 캡처를 이용해야 합니다. 캡처에는 [=]와 [&]이 존재합니다. [=]는 외부 변수를 값으로 전달받고 [&]는 참조로 전달받습니다.

[=]를 통해 전달받는 외부 변수는 값을 변경할 수 없습니다. 

#include <iostream>
using namespace std;
int main() {
    int nHeight = 170;
    [=](int nWeight) { 
      cout << "Height = " << nHeight << " Weight = " << nWeight << endl;
      nHeight = 200;
    } (50);

    cout << "Height = " << nHeight << endl;

    return 0;
}

전달받은 값을 변경하기 위해서는 [&] 캡처를 사용해야 합니다.

#include <iostream>
using namespace std;
int main() {
    int nHeight = 170;
    [&](int nWeight) { 
      cout << "Height = " << nHeight << " Weight = " << nWeight << endl;
      nHeight = 200;
    } (50);

    cout << "Height = " << nHeight << endl;

    return 0;
}

캡처를 더 세세하게 설정이 가능합니다. 전달 방식과 변수를 같이 기입하여 세밀하게 설정할 수 있습니다.

  • [&a] : 외부 변수 a만 참조로 전달받아 사용합니다. 다른 외부변수는 사용 불가합니다.
#include <iostream>
using namespace std;
int main() {
    int nHeight = 170;
    int nAge = 20;
    [&nHeight](int nWeight) { 
      cout << "Height = " << nHeight << " Weight = " << nWeight << endl;
      cout << "Age = " << nAge;
      nHeight = 200;
    } (50);

    cout << "Height = " << nHeight << endl;

    return 0;
}

  • [=, &a] : 외부 변수 모두 값으로 전달받아 사용하지만 a 변수만 참조로 전달받아 사용합니다.
#include <iostream>
using namespace std;
int main() {
    int nHeight = 170;
    int nAge = 20;
    [=, &nHeight](int nWeight) { 
      cout << "Height = " << nHeight << " Weight = " << nWeight << endl;
      cout << "Age = " << nAge << endl;
      nHeight = 200;
    } (50);

    cout << "Height = " << nHeight << endl;

    return 0;
}

  • [&, a] : 외부 변수 모두 참조 값으로 전달받아 사용하지만 a 변수만 값으로 전달받아 사용합니다.
#include <iostream>
using namespace std;
int main() {
    int nHeight = 170;
    int nAge = 20;
    [&, nHeight](int nWeight) { 
      cout << "Height = " << nHeight << " Weight = " << nWeight << endl;
      cout << "Age = " << nAge << endl;
      nHeight = 200;
    } (50);

    cout << "Height = " << nHeight << endl;

    return 0;
}

 

다음은 매개변수입니다. 매개변수는 기존 함수 선언과 마찬가지로 생략이 가능하며 사용하지 않을 경우에는 괄호 자체도 넣지 않아도 무관합니다.

#include <iostream>
using namespace std;
int main() {
    int nHeight = 170;
    [&] { 
      cout << "Height = " << nHeight << endl;
      nHeight = 200;
    } ();

    cout << "Height = " << nHeight << endl;

    return 0;
}

다음은 mutable 속성입니다. 캡처를 값에 의한 전달일 때 오류가 나지 않게 해 줍니다. 하지만 결국 값에 의한 전달이기 때문에 람다 내부에서 값을 변경해도 외부에서는 그대로인 것을 확인할 수 있습니다.

#include <iostream>
using namespace std;
int main() {
    int nHeight = 170;
    [=](int nWeight) mutable { 
      cout << "Height = " << nHeight << " Weight = " << nWeight << endl;
      nHeight = 200;
    } (50);

    cout << "Height = " << nHeight << endl;

    return 0;
}

throw는 예외 처리 관련 키워드입니다. 해당 키워드가 없어도 상관없습니다.

#include <iostream>
using namespace std;
int main() {
    int a = 5;
    [=] (int nDiv) throw() {
        try {
            if ( nDiv == 0 ) {
                throw 0;
            }
        cout << a/nDiv << endl;
        }
        catch (int e) {
            cout << "Exception";
        }
    } (0);
    return 0;
}

다음으로 반환형입니다. 기본적으로 람다 함수의 반환형은 void고 return을 사용하기 위해서는 반환형을 지정해야 합니다. 만약 따로 지정 안 하고 return 시에는 return에 맞춰 반환형이 결정되고 반환형을 지정했을 경우에 그에 맞춰 변경됩니다.

#include <iostream>
using namespace std;
int main() {
  int a = 63;
  cout << [=] (int nData)  {
    int nSum = a + nData;
    return nSum;
  } (0) << endl;

  cout << [=] (int nData)->char  {
    int nSum = a + nData;
    return nSum;
  } (0) << endl;
  
  return 0;
}

람다 함수는 아래와 같이도 사용할 수 있습니다. sort 함수 같이 함수를 인자로 넘기는 경우에 함수 자리에 람다 함수를 사용할 수 있습니다. auto 키워드를 이용해서 람다 함수를 변수로 지정하여 사용할 수 있습니다.

#include <iostream>
#include <algorithm>
using namespace std;

void printArr(int pArr[]) {
  for(int i=0;i<10;i++) {
    cout << pArr[i] << " ";
  } cout << endl;
}

int main() {
  int arr[10] = {3,8,19,1,4,22,3,24,51,29};
  printArr(arr);

  sort(arr, arr+10);
  printArr(arr);

  sort(arr, arr+10, [](int a, int b) { return a > b; });
  printArr(arr);

  sort(arr, arr+10);
  printArr(arr);

  auto des = [](int a, int b) { return a > b; };
  sort(arr, arr+10, des);
  printArr(arr);
  
  return 0;
}

 

728x90

+ Recent posts