Programing

같은 이름의 Lambda 캡처 및 매개 변수-다른 사람을 가리는 사람은 누구입니까?

lottogame 2020. 7. 9. 08:18
반응형

같은 이름의 Lambda 캡처 및 매개 변수-다른 사람을 가리는 사람은 누구입니까? (클랑 vs gcc)


auto foo = "You're using g++!";
auto compiler_detector = [foo](auto foo) { std::puts(foo); };
compiler_detector("You're using clang++!");
  • clang ++ 3.6.0 이상 인쇄 "clang ++을 사용하고 있습니다!" 캡처 foo 가 사용되지 않는 것에 대해 경고합니다 .

  • g ++ 4.9.0 이상 최신 버전 "G ++을 사용하고 있습니다!" 사용되지 않는 매개 변수 foo대해 경고합니다 .

어떤 컴파일러가 C ++ 표준을 더 정확하게 따르고 있습니까?

완드 박스 예제


업데이트 : 하단 인용문에서 코어 위원장이 약속 한대로 코드가 잘못 구성되었습니다 .

는 IF 식별자 A의 단순 캡처 는 AS 표시 선언자-ID 의 파라미터의 람다 선언자변수 선언 절 프로그램이 잘못 형성된다.


얼마 전에 람다에서 이름 조회와 관련된 몇 가지 문제가있었습니다. 그들은 N2927에 의해 해결되었습니다 .

새로운 문구는 더 이상 조회에 의존하여 캡처 된 엔터티의 사용을 다시 매핑하지 않습니다. 람다의 복합 명령문 이 두 단계로 처리되거나 해당 복합 명령문의 이름 이 클로저 유형의 멤버로 해석 될 수 있다는 해석을 더 명확하게 거부합니다 .

조회는 항상 lambda-expression 의 컨텍스트에서 수행되며 클로저 유형의 멤버 함수 본문으로의 변환은 "후에"수행되지 않습니다. [expr.prim.lambda] / 8 참조 :

람다 식화합물 문 수율 함수 바디 함수 호출 연산자 ([dcl.fct.def])로하지만, 이름 조회의 목적을 위해, [...] 상기 화합물 명령문 의 맥락에서 고려 람다 표현 . [ :

struct S1 {
  int x, y;
  int operator()(int);
  void f() {
    [=]()->int {
      return operator()(this->x+y);  // equivalent to: S1::operator()(this->x+(*this).y)
                                     // and this has type S1*
    }; 
  }
};

최종 예 ]

(이 예제는 또한 조회가 생성 된 클로저 유형의 캡처 멤버를 고려하지 않음을 분명히합니다.)

이름 foo은 캡처에서 (재) 선언되지 않습니다. 람다 식을 묶는 블록에서 선언됩니다. 매개 변수 foo는 해당 외부 블록에 중첩 된 블록에 선언됩니다 ( 명시 적으로 람다 매개 변수를 언급하는 [basic.scope.block] / 2 참조 ). 조회 순서는 내부 블록에서 외부 블록으로 명확 합니다 . 따라서 매개 변수를 선택해야합니다. 즉 Clang이 올바른 것입니다.

캡처 foo = ""대신 init-capture를 만들 foo려면 대답이 명확하지 않습니다. 캡처가 실제로 "block"이 지정되지 않은 선언을 유도 하기 때문 입니다. 나는 이것에 대한 핵심 의장에게 메시지를 보냈다.

이것은 2211 호입니다 (안타깝게도 open-std.org 사이트에 새로운 이슈 목록이 나타납니다. 불행히도 수많은 이슈에 대한 자리 표시 자만 있습니다.이 문제는 하나입니다. 월말 회의). CWG는 1 월 텔레 컨퍼런스에서이 문제에 대해 논의했으며 , 캡처 이름이 매개 변수 이름 인 경우 프로그램이 잘못된 형식을 만드는 것이 지시 사항입니다.


의미있는 답변을 제공하기 위해 질문에 몇 가지 의견을 모 으려고합니다.
우선 다음 사항에 유의하십시오.

  • 정적이 아닌 데이터 멤버는 각 복사 캡처 변수의 람다에 대해 선언됩니다.
  • 특정 경우, 람다는 클로즈 타입을 가지고 있는데,이 타입은 퍼블릭 인라인 템플릿 함수 호출 연산자로 명명 된 파라미터를 받아들입니다. foo

따라서 논리는 매개 변수가 캡처 된 변수를 다음과 같이 섀도 잉해야한다고 언뜻 알 수 있습니다.

struct Lambda {
    template<typename T> void operator()(T foo) const { /* ... */ }
    private: decltype(outer_foo) foo{outer_foo};
};

어쨌든 @nm은 복사 캡처 된 변수에 대해 선언 된 비 정적 데이터 멤버는 실제로 이름이 지정되지 않았다고 올바르게 지적했습니다. 즉, 명명되지 않은 데이터 멤버는 여전히 식별자 (즉 foo)를 통해 액세스됩니다 . 따라서 함수 호출 연산자의 매개 변수 이름은 해당 식별자를 여전히 가리야합니다 .
질문에 대한 의견에서 @nm이 올바르게 지적한 것처럼 :

원래 캡처 된 엔티티 [...]는 범위 규칙에 따라 정상적으로 음영 처리되어야합니다.

그 때문에 나는 clang이 옳다고 말합니다.

참고 : https://stackoverflow.com/questions/42088015/lambda-capture-and-parameter-with-same-name-who-shadows-the-other-clang-vs-g

반응형