C++의 람다 표현식

Lambda Expressions C



왜 람다 표현식인가?

다음 진술을 고려하십시오.

정수myInt= 52;

여기서 myInt는 식별자, lvalue입니다. 52는 리터럴, prvalue입니다. 오늘날에는 특별히 함수를 코딩하여 52의 위치에 놓을 수 있습니다. 이러한 함수를 람다식이라고 합니다. 다음 쇼트 프로그램도 고려하십시오.







#포함하다

사용 네임스페이스시간;

정수fn(정수~을 통해)

{

정수답변=~을 통해+ ;

반품답변;

}


정수기본()

{

fn(5);



반품 0;

}

오늘날에는 함수를 특별히 코딩하여 함수 호출 fn(5)의 인수 5의 위치에 넣을 수 있습니다. 이러한 함수를 람다 식이라고 합니다. 해당 위치의 람다 식(함수)은 prvalue입니다.

문자열 리터럴을 제외한 모든 리터럴은 prvalue입니다. 람다 식은 코드에서 리터럴로 적합한 특수 기능 디자인입니다. 익명(이름 없는) 함수입니다. 이 문서에서는 람다 식이라고 하는 새로운 C++ 기본 식에 대해 설명합니다. 이 기사를 이해하려면 C++에 대한 기본 지식이 필요합니다.

기사 내용

람다 식의 그림

다음 프로그램에서 람다 식인 함수가 변수에 할당됩니다.

#포함하다

사용 네임스페이스시간;

자동fn= [](정수멈추다)

{

정수답변=멈추다+ ;

반품답변;

};


정수기본()

{

자동변수=fn(2);

비용 <<변수<< 'N';


반품 0;

}

출력은 다음과 같습니다.

5

main() 함수 외부에는 변수 fn이 있습니다. 그 유형은 자동입니다. 이 상황에서 Auto는 int 또는 float와 같은 실제 유형이 할당 연산자(=)의 오른쪽 피연산자에 의해 결정됨을 의미합니다. 할당 연산자의 오른쪽에는 람다 표현식이 있습니다. 람다 식은 선행 반환 형식이 없는 함수입니다. 대괄호 []의 사용과 위치에 유의하십시오. 이 함수는 fn의 유형을 결정하는 int인 5를 반환합니다.

main() 함수에는 다음 문이 있습니다.

자동변수=fn(2);

즉, main() 외부의 fn은 함수의 식별자로 끝납니다. 암시적 매개변수는 람다 식의 매개변수입니다. variab의 유형은 auto입니다.

람다 표현식은 클래스 또는 구조체 정의와 마찬가지로 세미콜론으로 끝나고 세미콜론으로 끝납니다.

다음 프로그램에서 값 5를 반환하는 람다 식인 함수는 다른 함수에 대한 인수입니다.

#포함하다

사용 네임스페이스시간;

무효의기타(정수1번,정수 (*ptr)(정수))

{

정수2번= (*ptr)(2);

비용 <<1번<< '' <<2번<< 'N';

}


정수기본()

{

기타(4,[](정수멈추다)

{

정수답변=멈추다+ ;

반품답변;

});


반품 0;
}

출력은 다음과 같습니다.

오분의 사

여기에는 람다 식과 otherfn() 함수의 두 가지 함수가 있습니다. 람다 표현식은 main()에서 호출되는 otherfn()의 두 번째 인수입니다. 람다 함수(표현식)는 이 호출에서 세미콜론으로 끝나지 않습니다. 여기에서는 인수(독립 실행형 함수가 아님)이기 때문입니다.

otherfn() 함수 정의에서 람다 함수 매개변수는 함수에 대한 포인터입니다. 포인터의 이름은 ptr입니다. 이름 ptr은 otherfn() 정의에서 람다 함수를 호출하는 데 사용됩니다.

성명서,

정수2번= (*ptr)(2);

otherfn() 정의에서는 인수가 2인 람다 함수를 호출합니다. 호출의 반환 값인 람다 함수에서 '(*ptr)(2)'는 no2에 할당됩니다.

위의 프로그램은 또한 C++ 콜백 함수 체계에서 람다 함수를 사용하는 방법을 보여줍니다.

람다 표현의 일부

일반적인 람다 함수의 일부는 다음과 같습니다.

[] () {}
  • []는 캡처 절입니다. 아이템을 가질 수 있습니다.
  • ()는 매개변수 목록입니다.
  • {}는 함수 본문용입니다. 함수가 단독으로 있는 경우 세미콜론으로 끝나야 합니다.

캡처

람다 함수 정의는 변수에 할당하거나 다른 함수 호출에 대한 인수로 사용할 수 있습니다. 이러한 함수 호출에 대한 정의는 매개변수로 람다 함수 정의에 해당하는 함수에 대한 포인터를 가져야 합니다.

람다 함수 정의는 일반 함수 정의와 다릅니다. 전역 범위의 변수에 할당할 수 있습니다. 변수에 할당된 이 함수는 다른 함수 내에서 코딩할 수도 있습니다. 전역 범위 변수에 할당되면 해당 본문은 전역 범위의 다른 변수를 볼 수 있습니다. 일반 함수 정의 내의 변수에 할당되면 해당 본문은 capture 절의 도움말 []을 통해서만 함수 범위의 다른 변수를 볼 수 있습니다.

람다 인트로듀서(lambda-introducer)라고도 하는 캡처 절 []을 사용하면 변수를 주변(함수) 범위에서 람다 식의 함수 본문으로 보낼 수 있습니다. 람다 식의 함수 본문은 객체를 수신할 때 변수를 캡처한다고 합니다. 캡처 절 []이 없으면 변수를 주변 범위에서 람다 식의 함수 본문으로 보낼 수 없습니다. 다음 프로그램은 main() 함수 범위를 주변 범위로 사용하여 이를 보여줍니다.

#포함하다

사용 네임스페이스시간;

정수기본()

{

정수ID= 5;


자동fn= [ID]()

{

비용 <<ID<< 'N';

};

fn();


반품 0;

}

출력은 5 . id라는 이름이 없으면 [] 안에 람다 표현식이 main() 함수 범위의 변수 id를 보지 못했을 것입니다.

참조로 캡처

위의 캡처 절 사용 예는 값으로 캡처하는 것입니다(아래 세부 정보 참조). 참조로 캡처할 때 주변 범위의 변수 위치(예: 위의 id)는 람다 함수 본문 내에서 사용할 수 있습니다. 따라서 람다 함수 본문 내에서 변수의 값을 변경하면 주변 범위에서 동일한 변수의 값이 변경됩니다. 캡처 절에서 반복되는 각 변수는 이를 달성하기 위해 앰퍼샌드(&)가 앞에 옵니다. 다음 프로그램은 이를 보여줍니다.

#포함하다

사용 네임스페이스시간;

정수기본()

{

정수ID= 5; 뜨다피트= 2.3; 채널= '에게';

자동fn= [&ID,&피트,&채널]()

{

ID= 6;피트= 3.4;채널= 'NS';

};

fn();

비용 <<ID<< ',' <<피트<< ',' <<채널<< 'N';

반품 0;

}

출력은 다음과 같습니다.

6, 3.4, 나

람다 식의 함수 본문 내부의 변수 이름이 람다 식 외부의 동일한 변수에 대한 것인지 확인합니다.

가치로 포착

값으로 캡처할 때 주변 범위의 변수 위치 복사본을 람다 함수 본문 내에서 사용할 수 있습니다. 람다 함수 본문 내부의 변수는 복사본이지만 현재로서는 본문 내부에서 그 값을 변경할 수 없습니다. 값으로 캡처하기 위해 캡처 절에서 반복되는 각 변수 앞에는 아무 것도 오지 않습니다. 다음 프로그램은 이를 보여줍니다.

#포함하다

사용 네임스페이스시간;

정수기본()

{

정수ID= 5; 뜨다피트= 2.3; 채널= '에게';

자동fn= [아이디, 피트, 채널]()

{

// 아이디 = 6; 피트 = 3.4; 채널 = 'B';

비용 <<ID<< ',' <<피트<< ',' <<채널<< 'N';

};

fn();

ID= 6;피트= 3.4;채널= 'NS';

비용 <<ID<< ',' <<피트<< ',' <<채널<< 'N';

반품 0;

}

출력은 다음과 같습니다.

5, 2.3, 에이

6, 3.4, 나

주석 표시기가 제거되면 프로그램이 컴파일되지 않습니다. 컴파일러는 람다 식의 함수 본문 정의 내의 변수를 변경할 수 없다는 오류 메시지를 발행합니다. 변수는 람다 함수 내부에서 변경할 수 없지만 위 프로그램의 출력에서 ​​볼 수 있듯이 람다 함수 외부에서 변경할 수 있습니다.

캡처 혼합

다음 프로그램과 같이 참조로 캡처하는 것과 값으로 캡처하는 것을 혼합할 수 있습니다.

#포함하다

사용 네임스페이스시간;

정수기본()

{

정수ID= 5; 뜨다피트= 2.3; 채널= '에게'; 부울= 진실;


자동fn= [아이디, 피트,&ch,&]()

{

채널= 'NS';= 거짓;

비용 <<ID<< ',' <<피트<< ',' <<채널<< ',' <<<< 'N';

};

fn();


반품 0;

}

출력은 다음과 같습니다.

5, 2.3, B, 0

모두 캡처된 경우 참조용입니다.

캡처할 모든 변수가 참조로 캡처되는 경우 캡처 절에 & 하나만 있으면 충분합니다. 다음 프로그램은 이를 보여줍니다.

#포함하다

사용 네임스페이스시간;

정수기본()

{

정수ID= 5; 뜨다피트= 2.3; 채널= '에게'; 부울= 진실;


자동fn= [&]()

{

ID= 6;피트= 3.4;채널= 'NS';= 거짓;

};

fn();

비용 <<ID<< ',' <<피트<< ',' <<채널<< ',' <<<< 'N';


반품 0;

}

출력은 다음과 같습니다.

6, 3.4, B, 0

일부 변수가 참조로 캡처되고 다른 변수가 값으로 캡처되는 경우 다음 프로그램에서 볼 수 있듯이 하나의 &는 모든 참조를 나타내고 나머지는 각각 앞에 오지 않습니다.

사용 네임스페이스시간;

정수기본()

{

정수ID= 5; 뜨다피트= 2.3; 채널= '에게'; 부울= 진실;


자동fn= [&, 아이디, 피트]()

{

채널= 'NS';= 거짓;

비용 <<ID<< ',' <<피트<< ',' <<채널<< ',' <<<< 'N';

};

fn();


반품 0;

}

출력은 다음과 같습니다.

5, 2.3, B, 0

& 단독(즉, 식별자가 뒤따르지 않는 &)은 캡처 절의 첫 번째 문자여야 합니다.

모두 캡처된 경우 가치 기준:

캡처할 모든 변수가 값으로 캡처되어야 하는 경우 캡처 절에 = 하나만 있으면 충분합니다. 다음 프로그램은 이를 보여줍니다.

#포함하다

사용 네임스페이스시간;

정수기본()
{

정수ID= 5; 뜨다피트= 2.3; 채널= '에게'; 부울= 진실;


자동fn= [=]()

{

비용 <<ID<< ',' <<피트<< ',' <<채널<< ',' <<<< 'N';

};

fn();


반품 0;


}

출력은 다음과 같습니다.

5, 2.3, 에이, 1

메모 : = 현재로서는 읽기 전용입니다.

일부 변수는 값으로, 다른 변수는 참조로 캡처해야 하는 경우 다음 프로그램에서 볼 수 있듯이 하나의 =는 모든 읽기 전용으로 복사된 변수를 나타내고 나머지는 각각 &를 갖습니다.

#포함하다

사용 네임스페이스시간;

정수기본()

{

정수ID= 5; 뜨다피트= 2.3; 채널= '에게'; 부울= 진실;


자동fn= [=,&ch,&]()

{

채널= 'NS';= 거짓;

비용 <<ID<< ',' <<피트<< ',' <<채널<< ',' <<<< 'N';

};

fn();


반품 0;

}

출력은 다음과 같습니다.

5, 2.3, B, 0

= 단독으로 캡처 절의 첫 번째 문자여야 합니다.

Lambda 표현식을 사용한 클래식 콜백 함수 체계

다음 프로그램은 람다 식을 사용하여 고전적인 콜백 함수 체계를 수행하는 방법을 보여줍니다.

#포함하다

사용 네임스페이스시간;

*산출;


자동cba= []([])

{

산출=;

};



무효의메인기능(입력[],무효의 (*~을위한)([]))

{

(*~을위한)(입력);

비용<<'주요 기능을 위해'<<'N';

}


무효의fn()

{

비용<<'지금'<<'N';

}


정수기본()

{

입력[] = '콜백 함수';

메인기능(입력, cba);

fn();

비용<<산출<<'N';



반품 0;

}

출력은 다음과 같습니다.

주요 기능을 위해

지금

콜백 함수

람다 식 정의가 전역 범위의 변수에 할당되면 해당 함수 본문이 capture 절을 사용하지 않고도 전역 변수를 볼 수 있음을 기억하십시오.

후행 반환 유형

람다 식의 반환 유형은 auto입니다. 즉, 컴파일러가 반환 식(있는 경우)에서 반환 유형을 결정합니다. 프로그래머가 정말로 반환 유형을 표시하고 싶다면 다음 프로그램에서와 같이 수행할 것입니다.

#포함하다

사용 네임스페이스시간;

자동fn= [](정수멈추다) -> 정수

{

정수답변=멈추다+ ;

반품답변;

};


정수기본()

{

자동변수=fn(2);

비용 <<변수<< 'N';


반품 0;

}

출력은 5입니다. 매개변수 목록 뒤에 화살표 연산자가 입력됩니다. 그 다음에는 반환 유형(이 경우 int)이 옵니다.

폐쇄

다음 코드 세그먼트를 고려하십시오.

구조체클라

{

정수ID= 5;

채널= '에게';

}obj1, obj2;

여기서 Cla는 구조체 클래스의 이름입니다. Obj1과 obj2는 struct 클래스에서 인스턴스화될 두 개의 객체입니다. 람다 표현은 구현과 유사합니다. 람다 함수 정의는 일종의 클래스입니다. 람다 함수가 호출(호출)되면 개체는 해당 정의에서 인스턴스화됩니다. 이 객체를 클로저라고 합니다. 람다가 수행할 것으로 예상되는 작업을 수행하는 것은 클로저입니다.

그러나 위의 구조체와 같이 람다 식을 코딩하면 obj1 및 obj2가 해당 매개변수의 인수로 대체됩니다. 다음 프로그램은 이를 보여줍니다.

#포함하다

사용 네임스페이스시간;

자동fn= [](정수매개변수 1,정수매개변수2)

{

정수답변=매개변수1+매개변수2;

반품답변;

} (2,);


정수기본()

{

자동어디=fn;

비용 <<어디<< 'N';


반품 0;

}

출력은 5입니다. 인수는 괄호 안의 2와 3입니다. 람다 식 함수 호출 fn은 인수가 이미 람다 함수 정의의 끝에서 코딩되었기 때문에 인수를 취하지 않습니다.

결론

람다 식은 익명 함수입니다. 클래스와 객체의 두 부분으로 구성됩니다. 그 정의는 일종의 클래스입니다. 표현식이 호출되면 정의에서 객체가 형성됩니다. 이 객체를 클로저라고 합니다. 람다가 수행할 것으로 예상되는 작업을 수행하는 것은 클로저입니다.

람다 표현식이 외부 함수 범위에서 변수를 수신하려면 함수 본문에 비어 있지 않은 캡처 절이 필요합니다.