이름이 없는 익명 함수 객체(클로저)를 즉석에서 정의하여 사용하는 문법입니다. 주로 알고리즘, 콜백 함수 등 일회성 함수가 필요한 곳에 사용되어 코드의 간결성과 가독성을 높입니다.
람다 함수 외부의 변수에 어떻게 접근할지 지정
#include <iostream>
int main()
{
int x = 20;
int y = 10;
// 참조로 캡처, 람다 정의
auto simple = [&]()
{
std::cout << "x: " << x << ", y: " << y << std::endl;
x = 100;
};
// 람다 호출
simple();
// 참조한 람다 호출로 x값 변경
std::cout << "x: " << x << std::endl;
int a = 1, b = 2;
auto by_value = [a, b]() { return a + b; }; // 값으로 캡처
auto by_ref = [&a, &b]() { a++; b++; }; // 참조로 캡처
auto all_by_value = [=]() { return a + b; }; // 모든 변수를 값으로
auto all_by_ref = [&]() { a++; b++; }; // 모든 변수를 참조로
auto mixed = [a, &b]() { b = a + b; }; // 혼합 캡처
std::cout << "by_value 람다 호출 : " << by_value() << std::endl;
int f = 10;
// 변수 f 값으로 캡처한 변수의 복사본을 수정가능 호출할때마다 복사본의 값은 10씩 늘어난다.
auto fxa = [f]() mutable {int a = 10; f += 10; return a + f; };
std::cout << "fxa : " << fxa() << std::endl;
std::cout << "fxa : " << fxa() << std::endl;
std::cout << "f : " << f << std::endl;
}
// x: 20, y: 10
// x : 100
// by_value 람다 호출 : 3
// fxa : 30
// fxa : 40
// f : 10
#include <iostream>
#include <string>
int main()
{
// 일반화된 람다 : 매개변수 타입이 auto
auto print = [](auto value)
{
std::cout << value << std::endl;
};
print(42); // int
print(3.14); // double
print("Hello"); // const char*
print(std::string("World")); // std::string
// 여러 auto 매개변수 사용
auto add = [](auto a, auto b)
{
return a + b;
};
std::cout << add(10, 20) << std::endl; // 30 (int)
std::cout << add(1.5, 2.5) << std::endl; // 4.0 (double)
std::cout << add(std::string("Hello "), std::string("World")) << std::endl; // "Hello World"
}
#include <iostream>
#include <memory>
#include <vector>
int main()
{
// 1. 초기화 캡처로 새 변수 생성
int x = 10;
auto lambda1 = [value = x * 2]() {
std::cout << "value: " << value << std::endl; // 20
};
lambda1();
// 2. 이동 캡처 (move-only 타입인 unique_ptr 캡처)
auto ptr = std::make_unique<int>(100);
// C++11에서는 unique_ptr을 람다로 캡처할 방법이 없었음!
// C++14부터는 이동 캡처가 가능:
auto lambda2 = [ptr = std::move(ptr)]() {
std::cout << "ptr value: " << *ptr << std::endl;
};
lambda2();
lambda2();
// ptr은 이제 nullptr (소유권이 람다로 이동됨)
// 3. 벡터를 이동 캡처
std::vector<int> vec = { 1, 2, 3, 4, 5 };
auto lambda3 = [vec = std::move(vec)]() {
for (int n : vec)
{
std::cout << n << " ";
}
std::cout << std::endl;
};
lambda3();
lambda3();
// vec은 이제 비어있음 (이동됨)
}
std::move함수로 rvalue참조로 캐스팅이 되서 객체의 복사(Copy) 대신 자원의 소유권(Ownership)을 이전(Move)한다.
반환 타입 추론 개선 : 더 복잡한 경우에도 반환 타입을 자동으로 추론할 수 있게 됨
constexpr은 constant expression(상수 표현식)의 약자로, 컴파일 타임에 값을 계산할 수 있게하여 더 최적화된 코드를 생성하도록 돕는다.
[C/C++] constexpr 참고
#include <iostream>
int main()
{
// C++17: 람다 표현식 constexpr 명시적, 조건 충족 시 자동으로 constexpr
// 조건 불충족 - 명시해도 소용없음
constexpr auto square = [](int x) {
return x * x;
};
constexpr int result = square(5); // 컴파일 타임에 25 계산
std::cout << result << std::endl; // 25
// 배열 크기로 사용 가능
int arr[square(3)]; // int arr[9];
}
#include <iostream>
class Counter
{
public:
int count = 0;
auto getIncrementer()
{
// [*this]: 객체 전체를 복사
return [*this]() mutable {
count++; // 복사본의 count를 수정
std::cout << "[*this] 복사본 count: " << count << std::endl;
};
}
auto getIncrementer2()
{
// [this]: 객체 참조
return [this]() {
count++;
std::cout << "[this] 참조 count: " << count << std::endl;
};
}
};
int main()
{
Counter c;
auto inc = c.getIncrementer();
auto inc2 = c.getIncrementer2();
inc();
inc();
std::cout << "원본 count : " << c.count << std::endl;
inc2();
inc2();
std::cout << "원본 count : " << c.count << std::endl;
}