C++11에서 람다 표현식이란 무엇입니까? 언제 사용할까요? 도입 전에는 불가능했던 어떤 종류의 문제를 해결합니까?
몇 가지 예와 사용 사례가 유용할 것입니다.
질문자 :Nawaz
C++11에서 람다 표현식이란 무엇입니까? 언제 사용할까요? 도입 전에는 불가능했던 어떤 종류의 문제를 해결합니까?
몇 가지 예와 사용 사례가 유용할 것입니다.
std::for_each
및 std::transform
과 같은 유용한 일반 함수가 포함되어 있어 매우 편리합니다. 불행히도, 특히 적용하려는 펑터 가 특정 기능에 고유한 경우 사용하기가 상당히 번거로울 수 있습니다.
#include <algorithm> #include <vector> namespace { struct f { void operator()(int) { // do something } }; } void func(std::vector<int>& v) { ff; std::for_each(v.begin(), v.end(), f); }
f
한 번만 사용하고 그 특정 위치에서 사소한 일을 한 번만 수행하기 위해 전체 클래스를 작성하는 것은 과도한 것처럼 보입니다.
C++03에서는 functor를 로컬로 유지하기 위해 다음과 같이 작성하고 싶을 수 있습니다.
void func2(std::vector<int>& v) { struct { void operator()(int) { // do something } } f; std::for_each(v.begin(), v.end(), f); }
그러나 이것은 허용되지 않습니다. f
는 C++03 의 템플릿 함수에 전달할 수 없습니다.
struct f
를 대체하기 위해 인라인 익명 펑터를 작성할 수 있는 람다가 도입되었습니다. 작고 간단한 예의 경우 이것은 읽기가 더 깨끗할 수 있고(모든 것을 한 곳에 보관함) 유지 관리가 잠재적으로 더 간단할 수 있습니다(예: 가장 간단한 형식).
void func3(std::vector<int>& v) { std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ }); }
람다 함수는 익명 펑터를 위한 문법적 설탕일 뿐입니다.
간단한 경우에 람다의 반환 유형이 추론됩니다. 예:
void func4(std::vector<double>& v) { std::transform(v.begin(), v.end(), v.begin(), [](double d) { return d < 0.00001 ? 0 : d; } ); }
그러나 더 복잡한 람다를 작성하기 시작하면 컴파일러에서 반환 유형을 추론할 수 없는 경우를 빠르게 접하게 됩니다. 예:
void func4(std::vector<double>& v) { std::transform(v.begin(), v.end(), v.begin(), [](double d) { if (d < 0.0001) { return 0; } else { return d; } }); }
-> T
사용하여 람다 함수의 반환 유형을 명시적으로 지정할 수 있습니다.
void func4(std::vector<double>& v) { std::transform(v.begin(), v.end(), v.begin(), [](double d) -> double { if (d < 0.0001) { return 0; } else { return d; } }); }
지금까지 우리는 내부의 람다에 전달된 것 외에 다른 것을 사용하지 않았지만 람다 내에서 다른 변수도 사용할 수 있습니다. 다른 변수에 액세스하려면 캡처 절( []
을 사용할 수 있습니다. 이 절은 지금까지 다음 예제에서 사용되지 않았습니다. 예:
void func5(std::vector<double>& v, const double& epsilon) { std::transform(v.begin(), v.end(), v.begin(), [epsilon](double d) -> double { if (d < epsilon) { return 0; } else { return d; } }); }
&
및 =
각각 사용하여 지정할 수 있는 참조 및 값으로 캡처할 수 있습니다.
[&epsilon]
참조로 캡처[&]
참조로 람다에 사용된 모든 변수를 캡처합니다.[=]
값으로 람다에 사용된 모든 변수를 캡처합니다.[&, epsilon]
은 [&]와 같은 변수를 캡처하지만 값으로 엡실론을 캡처합니다.[=, &epsilon]
은 [=]와 같은 변수를 캡처하지만 참조에 의한 엡실론 생성된 operator()
는 const
이며 기본적으로 액세스할 때 캡처한다는 의미는 const
이는 동일한 입력을 사용하는 각 호출이 동일한 결과를 생성하는 효과가 있지만 생성된 operator()
const
가 아님을 요청하기 위해 람다를 mutable
것으로 표시할 수 있습니다.
람다 함수의 C++ 개념은 람다 미적분 및 함수 프로그래밍에서 시작됩니다. 람다는 재사용이 불가능하고 명명할 가치가 없는 짧은 코드 조각에 유용한(이론이 아닌 실제 프로그래밍에서) 명명되지 않은 함수입니다.
C++에서 람다 함수는 다음과 같이 정의됩니다.
[]() { } // barebone lambda
또는 모든 영광으로
[]() mutable -> T { } // T is the return type, still lacking throw()
[]
는 캡처 목록, ()
인수 목록 및 {}
함수 본문입니다.
캡처 목록은 함수 본문 내부에서 람다 외부에서 사용할 수 있는 항목과 방법을 정의합니다. 다음 중 하나일 수 있습니다.
[x, &y]
에서 위의 항목을 혼합할 수 있습니다.
인수 목록은 다른 C++ 함수와 동일합니다.
람다가 실제로 호출될 때 실행될 코드입니다.
람다에 return 문이 하나만 있는 경우 반환 유형을 생략할 수 있으며 암시적 유형이 decltype(return_statement)
입니다.
람다가 변경 가능(예: []() mutable { }
)으로 표시된 경우 값으로 캡처된 값을 변경할 수 있습니다.
ISO 표준에 의해 정의된 라이브러리는 람다의 이점을 많이 누리고 사용자가 액세스 가능한 범위의 작은 펑터로 코드를 어지럽힐 필요가 없기 때문에 사용성을 여러 수준으로 높입니다.
C++14에서 람다는 다양한 제안에 의해 확장되었습니다.
캡처 목록의 요소는 이제 =
로 초기화할 수 있습니다. 이것은 변수의 이름을 변경하고 이동하여 캡처할 수 있습니다. 표준에서 가져온 예:
int x = 4; auto y = [&r = x, x = x+1]()->int { r += 2; return x+2; }(); // Updates ::x to 6, and initializes y to 7.
std::move
로 캡처하는 방법을 보여주는 Wikipedia에서 가져온 것:
auto ptr = std::make_unique<int>(10); // See below for std::make_unique auto lambda = [ptr = std::move(ptr)] {return *ptr;};
이제 람다를 일반화할 수 있습니다( T
가 주변 범위의 어딘가에 유형 템플릿 인수인 경우 auto
T
와 동일합니다).
auto lambda = [](auto x, auto y) {return x + y;};
C++14는 모든 함수에 대해 추론된 반환 유형을 허용하고 return expression;
. 이것은 람다로도 확장됩니다.
람다 표현식은 일반적으로 알고리즘을 캡슐화하여 다른 함수에 전달할 수 있도록 하는 데 사용됩니다. 그러나 정의 즉시 람다를 실행할 수 있습니다 .
[&](){ ...your code... }(); // immediately executed lambda expression
기능적으로 동등하다
{ ...your code... } // simple code block
이것은 람다 표현식을 복잡한 함수를 리팩토링하기 위한 강력한 도구로 만듭니다. 위와 같이 람다 함수에서 코드 섹션을 래핑하여 시작합니다. 명시적 매개변수화 프로세스는 각 단계 후 중간 테스트를 통해 점진적으로 수행할 수 있습니다. 코드 블록이 완전히 매개변수화되면( &
제거로 설명됨) 코드를 외부 위치로 이동하여 정상적인 기능으로 만들 수 있습니다.
마찬가지로 람다 식을 사용 하여 알고리즘의 결과를 기반으로 변수 를 초기화할 수 있습니다.
int a = []( int b ){ int r=1; while (b>0) r*=b--; return r; }(5); // 5!
프로그램 논리를 분할하는 방법 으로 다른 람다 식에 대한 인수로 람다 식을 전달하는 것이 유용할 수도 있습니다.
[&]( std::function<void()> algorithm ) // wrapper section { ...your wrapper code... algorithm(); ...your wrapper code... } ([&]() // algorithm section { ...your algorithm code... });
또한 람다 표현식을 사용하면 중복 논리를 방지하는 편리한 방법이 될 수 있는 명명된 중첩 함수를 생성할 수 있습니다. 명명된 람다를 사용하면 중요하지 않은 함수를 다른 함수에 매개변수로 전달할 때 (익명의 인라인 람다와 비교하여) 눈에 조금 더 쉬운 경향이 있습니다. 참고: 닫는 중괄호 뒤에 오는 세미콜론을 잊지 마십시오.
auto algorithm = [&]( double x, double m, double b ) -> double { return m*x+b; }; int a=algorithm(1,2,3), b=algorithm(4,5,6);
후속 프로파일링에서 함수 개체에 대한 상당한 초기화 오버헤드가 드러날 경우 이를 일반 함수로 다시 작성하도록 선택할 수 있습니다.
답변
Q: C++11에서 람다 표현식이란 무엇입니까?
A: 내부적으로는 operator() const 를 오버로드하여 자동 생성된 클래스의 객체입니다. 이러한 객체를 클로저 라고 하며 컴파일러에 의해 생성됩니다. 이 '클로저' 개념은 C++11의 바인드 개념에 가깝습니다. 그러나 람다는 일반적으로 더 나은 코드를 생성합니다. 그리고 클로저를 통한 호출은 전체 인라인을 허용합니다.
Q: 언제 사용하나요?
A: "간단하고 작은 논리"를 정의하고 컴파일러에게 이전 질문에서 생성을 수행하도록 요청합니다. operator() 내부에 포함하려는 일부 표현식을 컴파일러에 제공합니다. 다른 모든 것들은 컴파일러가 당신에게 생성할 것입니다.
Q: 도입 전에는 불가능했던 어떤 종류의 문제를 해결합니까?
A: 사용자 정의 추가, 빼기 작업을 위한 함수 대신 연산자 오버로딩과 같은 일종의 구문 설탕입니다. 하지만 1-3줄의 실제 논리를 일부 클래스에 래핑하기 위해 불필요한 코드 줄을 더 많이 절약할 수 있습니다. 일부 엔지니어는 라인 수가 적으면 오류가 발생할 가능성이 적다고 생각합니다(저도 그렇게 생각합니다).
사용 예
auto x = [=](int arg1){printf("%i", arg1); }; void(*f)(int) = x; f(1); x(1);
질문에 포함되지 않은 람다에 대한 추가 정보. 관심이 없으면 이 섹션을 무시하세요.
1. 캡처된 값. 캡처할 수 있는 것
1.1. 람다에서 정적 저장 기간이 있는 변수를 참조할 수 있습니다. 모두 잡혀 있습니다.
1.2. "값별" 캡처 값에 람다를 사용할 수 있습니다. 이러한 경우 캡처된 변수는 함수 개체(클로저)에 복사됩니다.
[captureVar1,captureVar2](int arg1){}
1.3. 당신은 참조를 캡처할 수 있습니다. & -- 이 컨텍스트에서 포인터가 아닌 참조를 의미합니다.
[&captureVar1,&captureVar2](int arg1){}
1.4. 값 또는 참조로 모든 비 정적 변수를 캡처하는 표기법이 있습니다.
[=](int arg1){} // capture all not-static vars by value [&](int arg1){} // capture all not-static vars by reference
1.5. 값 또는 참조로 모든 비 정적 변수를 캡처하고 smth를 지정하는 표기법이 있습니다. 더. 예: 모든 비정적 변수를 값으로 캡처하지만 참조 캡처 Param2로 캡처
[=,&Param2](int arg1){}
모든 비정적 변수를 참조로 캡처하지만 값 캡처 Param2로 캡처
[&,Param2](int arg1){}
2. 반환 유형 공제
2.1. 람다가 하나의 표현식인 경우 람다 반환 유형을 추론할 수 있습니다. 또는 명시적으로 지정할 수 있습니다.
[=](int arg1)->trailing_return_type{return trailing_return_type();}
람다에 하나 이상의 표현식이 있는 경우 후행 반환 유형을 통해 반환 유형을 지정해야 합니다. 또한 자동 함수와 멤버 함수에도 유사한 구문을 적용할 수 있습니다.
3. 캡처된 값. 캡처할 수 없는 것
3.1. 개체의 멤버 변수가 아닌 로컬 변수만 캡처할 수 있습니다.
4. 변환
4.1!! Lambda는 함수 포인터가 아니며 익명 함수도 아니지만 캡처가 없는 람다는 암시적으로 함수 포인터로 변환될 수 있습니다.
추신
람다 문법 정보에 대한 자세한 내용은 프로그래밍 언어 C++ 작업 초안 #337, 2012-01-16, 5.1.2에서 찾을 수 있습니다. 람다 식, p.88
C++14에서는 "초기화 캡처"로 명명된 추가 기능이 추가되었습니다. 클로저 데이터 멤버의 임의 선언을 수행할 수 있습니다.
auto toFloat = [](int value) { return float(value);}; auto interpolate = [min = toFloat(0), max = toFloat(255)](int value)->float { return (value - min) / (max - min);};
람다 함수는 인라인으로 생성하는 익명 함수입니다. 일부 설명(예: http://www.stroustrup.com/C++11FAQ.html#lambda )과 같이 변수를 캡처할 수 있지만 몇 가지 제한 사항이 있습니다. 예를 들어 다음과 같은 콜백 인터페이스가 있는 경우
void apply(void (*f)(int)) { f(10); f(20); f(30); }
그 자리에서 함수를 작성하여 아래에 적용하기 위해 전달된 것과 같이 사용할 수 있습니다.
int col=0; void output() { apply([](int data) { cout << data << ((++col % 10) ? ' ' : '\n'); }); }
그러나 당신은 이것을 할 수 없습니다:
void output(int n) { int col=0; apply([&col,n](int data) { cout << data << ((++col % 10) ? ' ' : '\n'); }); }
C++11 표준의 한계 때문입니다. 캡처를 사용하려면 라이브러리에 의존해야 하고
#include <functional>
(또는 간접적으로 얻기 위한 알고리즘과 같은 다른 STL 라이브러리) 다음과 같이 일반 함수를 매개변수로 전달하는 대신 std::function으로 작업합니다.
#include <functional> void apply(std::function<void(int)> f) { f(10); f(20); f(30); } void output(int width) { int col; apply([width,&col](int data) { cout << data << ((++col % width) ? ' ' : '\n'); }); }
lambda expression
에 대한 가장 좋은 설명 중 하나는 C++ Bjarne Stroustrup의 저자가 그의 책 ***The C++ Programming Language***
11장( ISBN-13: 978-0321563842 )에서 제공한 것입니다.
What is a lambda expression?
람다 식 람다로 때때로 람다 함수라고 또는 (엄밀히 말하자면 부정확하지만 놓고)을 정의하고 익명 함수 객체를 사용하는 단순화 된 표기이다. operator()로 명명된 클래스를 정의하는 대신 나중에 해당 클래스의 객체를 만들고 마지막으로 호출하는 대신 약식을 사용할 수 있습니다.
When would I use one?
이것은 연산을 알고리즘에 인수로 전달하려는 경우에 특히 유용합니다. 그래픽 사용자 인터페이스(및 다른 곳)의 컨텍스트에서 이러한 작업을 종종 콜백 이라고 합니다.
What class of problem do they solve that wasn't possible prior to their introduction?
여기에서 람다 식으로 수행된 모든 작업은 람다 식 없이도 해결할 수 있지만 훨씬 더 많은 코드와 훨씬 더 복잡해집니다. 람다 식 이것은 코드를 최적화하는 방법이자 코드를 더 매력적으로 만드는 방법입니다. Stroustup의 슬픈 말:
효과적인 최적화 방법
Some examples
람다 식을 통해
void print_modulo(const vector<int>& v, ostream& os, int m) // output v[i] to os if v[i]%m==0 { for_each(begin(v),end(v), [&os,m](int x) { if (x%m==0) os << x << '\n'; }); }
또는 기능을 통해
class Modulo_print { ostream& os; // members to hold the capture list int m; public: Modulo_print(ostream& s, int mm) :os(s), m(mm) {} void operator()(int x) const { if (x%m==0) os << x << '\n'; } };
또는
void print_modulo(const vector<int>& v, ostream& os, int m) // output v[i] to os if v[i]%m==0 { class Modulo_print { ostream& os; // members to hold the capture list int m; public: Modulo_print (ostream& s, int mm) :os(s), m(mm) {} void operator()(int x) const { if (x%m==0) os << x << '\n'; } }; for_each(begin(v),end(v),Modulo_print{os,m}); }
필요한 경우 아래와 같이 lambda expression
이름을 지정할 수 있습니다.
void print_modulo(const vector<int>& v, ostream& os, int m) // output v[i] to os if v[i]%m==0 { auto Modulo_print = [&os,m] (int x) { if (x%m==0) os << x << '\n'; }; for_each(begin(v),end(v),Modulo_print); }
또는 다른 간단한 샘플을 가정합니다.
void TestFunctions::simpleLambda() { bool sensitive = true; std::vector<int> v = std::vector<int>({1,33,3,4,5,6,7}); sort(v.begin(),v.end(), [sensitive](int x, int y) { printf("\n%i\n", x < y); return sensitive ? x < y : abs(x) < abs(y); }); printf("sorted"); for_each(v.begin(), v.end(), [](int x) { printf("x - %i;", x); } ); }
다음에 생성합니다
0
1
0
1
0
1
0
1
0
1
0 정렬 x - 1, x - 3, x - 4, x - 5, x - 6, x - 7, x - 33,
[]
- 이것은 캡처 목록 또는 lambda introducer
. lambdas
가 로컬 환경에 액세스할 필요가 없으면 사용할 수 있습니다.
책에서 인용:
람다 식의 첫 번째 문자는 항상 [ . 람다 소개자는 다양한 형태를 취할 수 있습니다.
• [] : 빈 캡처 목록입니다. 이는 주변 컨텍스트의 로컬 이름을 람다 본문에 사용할 수 없음을 의미합니다. 이러한 람다 식의 경우 데이터는 인수 또는 비지역 변수에서 가져옵니다.
• [&] : 참조에 의한 암시적 캡처. 모든 지역 이름을 사용할 수 있습니다. 모든 지역 변수는 참조로 액세스됩니다.
• [=] : 값으로 암시적으로 캡처합니다. 모든 지역 이름을 사용할 수 있습니다. 모든 이름은 람다 식 호출 시점에서 가져온 지역 변수의 복사본을 참조합니다.
• [capture-list]: 명시적 캡처; capture-list는 참조 또는 값으로 캡처(즉, 개체에 저장)할 지역 변수의 이름 목록입니다. &가 앞에 오는 이름을 가진 변수는 참조로 캡처됩니다. 다른 변수는 값으로 캡처됩니다. 캡처 목록에는 이 항목과 이름 뒤에 ...가 요소로 포함될 수도 있습니다.
• [&, capture-list] : 목록에 언급되지 않은 이름을 가진 모든 지역 변수를 참조로 암시적으로 캡처합니다. 캡처 목록에는 이것을 포함할 수 있습니다. 나열된 이름 앞에 &가 올 수 없습니다. 캡처 목록에 명명된 변수는 값으로 캡처됩니다.
• [=, capture-list] : 목록에 언급되지 않은 이름을 가진 모든 지역 변수를 값으로 암시적으로 캡처합니다. 캡처 목록에는 이것을 포함할 수 없습니다. 나열된 이름 앞에 &가 있어야 합니다. 캡처 목록에 명명된 변수는 참조로 캡처됩니다.
&가 앞에 오는 지역 이름은 항상 참조로 캡처되고 &가 앞에 오지 않는 지역 이름은 항상 값으로 캡처됩니다. 참조에 의한 캡처만 호출 환경에서 변수를 수정할 수 있습니다.
Additional
Lambda expression
형식
추가 참조:
C++의 람다는 "이동 중 사용 가능한 기능"으로 처리됩니다. 네, 문자 그대로 이동 중에도 정의할 수 있습니다. 사용해; 부모 함수 범위가 완료되면 람다 함수가 사라집니다.
C++는 C++ 11에 도입했고 모든 사람이 가능한 모든 곳에서 사용하기 시작했습니다. 예제와 람다가 무엇인지 https://en.cppreference.com/w/cpp/language/lambda에서 찾을 수 있습니다.
나는 거기에 없지만 모든 C++ 프로그래머가 알아야 할 필수적인 것을 설명할 것입니다.
람다는 어디에서나 사용할 수 없으며 모든 기능을 람다로 대체할 수 없습니다. 또한 일반 기능에 비해 가장 빠른 속도도 아닙니다. 람다가 처리해야 하는 약간의 오버헤드가 있기 때문입니다.
어떤 경우에는 줄 수를 줄이는 데 확실히 도움이 될 것입니다. 기본적으로 동일한 함수에서 한 번 이상 호출되는 코드 섹션에 사용할 수 있으며 해당 코드 조각은 다른 곳에서 필요하지 않으므로 독립 실행형 함수를 만들 수 있습니다.
다음은 람다의 기본 예와 백그라운드에서 일어나는 일입니다.
사용자 코드:
int main() { // Lambda & auto int member=10; auto endGame = [=](int a, int b){ return a+b+member;}; endGame(4,5); return 0; }
컴파일이 확장하는 방법:
int main() { int member = 10; class __lambda_6_18 { int member; public: inline /*constexpr */ int operator()(int a, int b) const { return a + b + member; } public: __lambda_6_18(int _member) : member{_member} {} }; __lambda_6_18 endGame = __lambda_6_18{member}; endGame.operator()(4, 5); return 0; }
보시다시피 사용할 때 어떤 종류의 오버헤드가 추가되는지 알 수 있습니다. 따라서 모든 곳에서 사용하는 것은 좋지 않습니다. 적용되는 곳에서 사용할 수 있습니다.
글쎄, 내가 발견한 실용적인 용도 중 하나는 보일러 플레이트 코드를 줄이는 것입니다. 예를 들어:
void process_z_vec(vector<int>& vec) { auto print_2d = [](const vector<int>& board, int bsize) { for(int i = 0; i<bsize; i++) { for(int j=0; j<bsize; j++) { cout << board[bsize*i+j] << " "; } cout << "\n"; } }; // Do sth with the vec. print_2d(vec,x_size); // Do sth else with the vec. print_2d(vec,y_size); //... }
bsize
경우에 대해 뭔가를 해야 할 수도 있습니다. 물론 함수를 생성할 수도 있지만 영혼 사용자 함수의 범위 내에서 사용을 제한하려면 어떻게 해야 할까요? 람다의 특성은 이 요구 사항을 충족하며 저는 이 경우에 사용합니다.
이것이 해결하는 한 가지 문제: const 멤버를 초기화하기 위해 출력 매개변수 함수를 사용하는 생성자 호출에 대해 람다보다 간단한 코드
출력을 출력 매개변수로 되돌려 값을 설정하는 함수를 호출하여 클래스의 const 멤버를 초기화할 수 있습니다.
C++ 11에서는 짧은 코드 조각에 사용할 수 있는 인라인 함수를 작성할 수 있도록 람다 표현식을 도입했습니다.
[ capture clause ] (parameters) -> return-type { definition of method }
일반적으로 람다 식의 반환 유형은 컴파일러 자체에 의해 평가되며 명시적으로 지정할 필요가 없으며 -> 반환 유형 부분을 무시할 수 있지만 조건문과 같이 복잡한 경우에는 컴파일러가 반환을 확인할 수 없습니다. 유형을 지정하고 이를 지정해야 합니다.
// C++ program to demonstrate lambda expression in C++ #include <bits/stdc++.h> using namespace std; // Function to print vector void printVector(vector<int> v) { // lambda expression to print vector for_each(v.begin(), v.end(), [](int i) { std::cout << i << " "; }); cout << endl; } int main() { vector<int> v {4, 1, 3, 5, 2, 3, 1, 7}; printVector(v); // below snippet find first number greater than 4 // find_if searches for an element for which // function(third argument) returns true vector<int>:: iterator p = find_if(v.begin(), v.end(), [](int i) { return i > 4; }); cout << "First number greater than 4 is : " << *p << endl; // function to sort vector, lambda expression is for sorting in // non-decreasing order Compiler can make out return type as // bool, but shown here just for explanation sort(v.begin(), v.end(), [](const int& a, const int& b) -> bool { return a > b; }); printVector(v); // function to count numbers greater than or equal to 5 int count_5 = count_if(v.begin(), v.end(), [](int a) { return (a >= 5); }); cout << "The number of elements greater than or equal to 5 is : " << count_5 << endl; // function for removing duplicate element (after sorting all // duplicate comes together) p = unique(v.begin(), v.end(), [](int a, int b) { return a == b; }); // resizing vector to make size equal to total different number v.resize(distance(v.begin(), p)); printVector(v); // accumulate function accumulate the container on the basis of // function provided as third argument int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int f = accumulate(arr, arr + 10, 1, [](int i, int j) { return i * j; }); cout << "Factorial of 10 is : " << f << endl; // We can also access function by storing this into variable auto square = [](int i) { return i * i; }; cout << "Square of 5 is : " << square(5) << endl; }
산출
4 1 3 5 2 3 1 7 First number greater than 4 is : 5 7 5 4 3 3 2 1 1 The number of elements greater than or equal to 5 is : 2 7 5 4 3 2 1 Factorial of 10 is : 3628800 Square of 5 is : 25
람다 식은 바깥쪽 범위에서 변수에 액세스할 수 있으므로 일반 함수보다 더 많은 기능을 가질 수 있습니다. 세 가지 방법으로 범위를 둘러싸는 외부 변수를 캡처할 수 있습니다.
변수 캡처에 사용되는 구문:
#include <bits/stdc++.h> using namespace std; int main() { vector<int> v1 = {3, 1, 7, 9}; vector<int> v2 = {10, 2, 7, 16, 9}; // access v1 and v2 by reference auto pushinto = [&] (int m) { v1.push_back(m); v2.push_back(m); }; // it pushes 20 in both v1 and v2 pushinto(20); // access v1 by copy [v1]() { for (auto p = v1.begin(); p != v1.end(); p++) { cout << *p << " "; } }; int N = 5; // below snippet find first number greater than N // [N] denotes, can access only N by value vector<int>:: iterator p = find_if(v1.begin(), v1.end(), [N](int i) { return i > N; }); cout << "First number greater than 5 is : " << *p << endl; // function to count numbers greater than or equal to N // [=] denotes, can access all variable int count_N = count_if(v1.begin(), v1.end(), [=](int a) { return (a >= N); }); cout << "The number of elements greater than or equal to 5 is : " << count_N << endl; }
산출:
First number greater than 5 is : 7 The number of elements greater than or equal to 5 is : 3
출처 : http:www.stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11
pip를 사용하여 특정 패키지 버전 설치 (0) | 2022.01.14 |
---|---|
... 값에 삽입( SELECT ... FROM ... ) (0) | 2022.01.14 |
Git 기록에서 커밋된 코드를 grep(검색)하는 방법 (0) | 2022.01.08 |
정의되지 않은 참조/해결되지 않은 외부 기호 오류는 무엇이며 어떻게 수정합니까? (0) | 2022.01.08 |
var 키워드의 목적은 무엇이며 언제 사용(또는 생략)해야 합니까? (0) | 2022.01.08 |