왜 이것을 람다에서 참조 ( '& this')로 캡처 할 수 없습니까?


91

this람다에서 캡처 (개체 속성 수정) 하는 올바른 방법 은 다음과 같습니다.

auto f = [this] () { /* ... */ };

그러나 나는 내가 본 다음과 같은 특징이 궁금합니다.

class C {
    public:
        void foo() {
            // auto f = [] () { // this not captured
            auto f = [&] () { // why does this work?
            // auto f = [&this] () { // Expected ',' before 'this'
            // auto f = [this] () { // works as expected
                x = 5;
            };
            f();
        }

    private:
        int x;
};

내가 혼란스럽고 대답하고 싶은 이상한 점은 다음과 같은 이유입니다.

auto f = [&] () { /* ... */ }; // capture everything by reference

그리고 내가 this참조로 명시 적으로 캡처 할 수없는 이유 :

auto f = [&this] () { /* ... */ }; // a compiler error as seen above.

6
당신은 왜 것이라고 수 있습니다? 포인터에 대한 참조 이제까지 생각할 유용 할 수있는 것들의 측면에서 : this변경할 수 없습니다, 더 빨리 참조를 만들기 위해 큰 충분하지 않습니다 ... 그리고 어쨌든 , 실제로 존재하지 않는 이있다, 그래서 실제 수명이 없습니다. 즉, 그에 대한 참조는 정의에 따라 달라집니다. thislvalue가 아니라 prvalue입니다.
underscore_d

답변:


111

[&this]작동하지 않는 이유 는 구문 오류 때문입니다. 의 각 쉼표로 구분 된 매개 변수는 다음 lambda-introducercapture같습니다.

capture:
    identifier
    & identifier
    this

&this구문 상 허용되지 않음을 알 수 있습니다 . 허용되지 않는 이유 this는 작은 const 포인터 이기 때문에 참조 로 캡처하고 싶지 않기 때문 입니다. 값으로 만 전달하고 싶을 것입니다. 따라서 언어는 this참조로 캡처 하는 것을 지원하지 않습니다 .

캡처에 this명시 적으로 사용할 수 [this]는 AS lambda-introducer.

첫 번째 capture는 다음 중 하나 일 수 있습니다 capture-default.

capture-default:
    &
    =

이것은 내가 사용하는 모든 것을 참조 ( &) 또는 값 ( =) 별로 자동으로 캡처하는 것을 의미합니다. 그러나 처리 this는 특별합니다. 두 경우 모두 이전에 제공된 이유 때문에 값으로 캡처됩니다 (기본 캡처를 사용하더라도 &일반적으로 참조로 캡처).

5.1.2.7/8 :

이름 조회 (3.4)를 위해 this(9.3.2) 의 유형과 값을 결정하고 비 정적 클래스 멤버를 참조하는 id- 표현식을 (*this)(9.3.1), 복합 문 [OF]을 사용하여 클래스 멤버 액세스 표현식 으로 변환합니다. THE LAMBDA]는 lambda-expression의 맥락에서 고려됩니다.

따라서 람다는 멤버 이름을 사용할 때 둘러싸는 멤버 함수의 일부인 것처럼 작동하므로 (예에서 name 사용과 같이 x) this멤버 함수와 마찬가지로 "암시 적 사용"을 생성 합니다.

lambda-capture가 capture-default를 포함하는 경우 lambda-capture &의 식별자 앞에 &. lambda-capture가 capture-default를 포함하는 =경우 lambda-capture는 포함하지 않아야하며 포함 된 this각 식별자 앞에 &. 식별자 또는 this람다 캡처에서 두 번 이상 나타나지 않아야합니다.

당신이 사용할 수 있도록 [this], [&], [=]또는 [&,this]A와 lambda-introducer캡처하는 this값으로 포인터를.

그러나 [&this][=, this]잘못 형성된다. 마지막 경우에 gcc 는 오류 [=,this]explicit by-copy capture of ‘this’ redundant with by-copy capture default아니라이를 경고 합니다.


3
@KonradRudolph : 가치로 어떤 것을 캡처하고 참조로 다른 것을 캡처하려면 어떻게해야합니까? 아니면 캡처 한 내용을 매우 명확하게하고 싶습니까?
Xeo

2
@KonradRudolph : 안전 기능입니다. 의도하지 않은 이름을 실수로 캡처 할 수 있습니다.
Andrew Tomazos

8
@KonradRudolph : 블록 수준 구조는 사용하는 개체에 대한 포인터를 새로운 보이지 않는 익명 형식으로 마술처럼 복사하지 않으며, 식에서 개체 이름을 사용하여 둘러싸는 범위에서 살아남을 수 있습니다. Lambda 캡처는 훨씬 더 위험한 비즈니스입니다.
Andrew Tomazos

5
@KonradRudolph 나는 " [&]제어 구조로 전달할 블록을 만드는 것과 같은 작업을 수행 하는 경우 사용"이라고 말하고 싶지만 덜 간단한 목적으로 사용할 람다를 생성하는 경우 명시 적으로 캡처합니다. [&]람다가 현재 범위보다 오래 지속될 경우 끔찍한 아이디어입니다. 그러나 람다의 많은 사용은 블록을 제어 구조로 전달하는 방법 일 뿐이며 블록은 범위에서 생성 된 블록보다 오래 지속되지 않습니다.
Yakk-Adam Nevraumont

2
@Ruslan : 아니요, this키워드이며 this식별자가 아닙니다.
Andrew Tomazos

6

표준은 &this캡처 목록에 없기 때문에 :

N4713 8.4.5.2 캡처 :

lambda-capture:
    capture-default
    capture-list
    capture-default, capture-list

capture-default:
    &
    =
capture-list:
    capture...opt
    capture-list, capture...opt
capture:
    simple-capture
    init-capture
simple-capture:
    identifier
    &identifier
    this
    * this
init-capture:
    identifier initializer
    &identifier initializer
  1. 람다 캡처를 위해 식은 잠재적으로 다음과 같이 로컬 엔터티를 참조합니다.

    7.3 this 표현은 잠재적으로 * this를 참조합니다.

따라서 표준 보증 this*this유효하며 &this유효하지 않습니다. 또한, 촬영 this촬상 수단 *this(a 좌변 객체 자체 임) 을 참조하여 , 대신 캡처 this포인터 !


*this값으로
sp2danny
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.