“int main () {(([] () {}) ());}”은 어떻게 C ++에 유효합니까?


271

나는 최근에 다음과 같은 난해한 코드를 보았습니다.

int main(){(([](){})());}

더 읽기 쉽게하려면 다음과 같이 다시 포맷하십시오.

int main(){
    (([](){})());   //  Um... what?!?!
}

그러나 (([](){})())유효한 코드가 어떻 습니까?

  • 함수 포인터 구문처럼 보이지 않습니다.
  • 연산자 오버로드 트릭이 될 수 없습니다. 코드는 그대로 컴파일됩니다.

Google은이 모든 기호 검색에 큰 도움이되지 않았습니다. 그러나 Visual Studio 2010에서 컴파일되어 아무것도 출력하지 않습니다. 오류와 경고가 없었습니다. 따라서 유효한 코드처럼 보입니다.

JavascriptC 함수 포인터 외부에서 기괴한 유효한 코드를 본 적이 없습니다 .

누군가 이것이 이것이 어떻게 유효한 C ++인지 설명 할 수 있습니까?


94
야! 그것은 내꺼 다. "Don't sweat it. We have int main(){(([](){})());} which is valid C++" (11 월 9 일 채팅)
sehe

31
그것은 C ++ 11 람다 폐쇄의

7
@Mysticial-이 코드는 쓸모가 없기 때문에 당신을 신비하게 만듭니다. 이 람다가 무언가를 할 경우, 함수 포인터와 비슷한 구문을 가지고 있음을 알 수 있습니다 (밀접하게 관련되어 있음).
SChepurin

14
@Mysticial- "6 년의 C ++"-람다는 C ++ 11에 방금 추가되었으므로 1 년 전이나 그 어느 누구도 경험이 없습니다.
피트 베커

50
여기 URL은 아주 재미 있습니다 : "how-is-int-main-valid-c"
tckmn

답변:


283

이 코드는 기본적으로 빈 람다를 호출합니다.

처음부터 시작합시다 : [](){}람다 식 입니다.

그런 다음 C 및 C ++에서 표현식을 Parens로 랩핑 할 수 있으며 표현식 없이 작성 하는 것과 똑같은 동작을 수행 하므로 람다 주변의 첫 번째 Parens 쌍이 수행됩니다. 우리는 지금에 ([](){})있습니다.

그런 다음 ()첫 번째 줄 바꿈 후 (빈) 람다를 호출합니다. 우리는 지금([](){})()

전체 표현이 다시 괄호로 싸여지고 우리는 얻는다 (([](){})()).

마지막으로 ;진술을 끝냅니다. 에 도착 (([](){})());합니다.


†있다 일부 와 마찬가지로 C에서 적어도 코너의 경우는, ++ T a_var; 사이에 차이가있어 decltype(a_var)하고decltype((a_var)) .


7
단검을 놓쳤다.
R. Martinho Fernandes 10

33
@ R.MartinhoFernandes : 여전히 누군가에 갇혀있어서 검색해야했습니다.
Xeo

1
식 주위에 ()를 추가하면 의미가 변경되는 경우 를 정확하게 언급하여 투표했습니다 . 그러나 나는 그 질문과 관련이 없다는 것을 기억했습니다. 좋은 답변
sehe

2
괄호는 또한 가장 성가신 파싱 동음의 경우에는 프로그램의 의미를 변화 : B foo(A())푸 함수 (유일한 파라미터로 함수에 대한 포인터를 취득하고, B 복귀)에 반해이다 B foo((A()))foo를하는 B 객체는 생성자 촬영을 호출하여 구성 a 객체 (이 경우 익명 임시 인스턴스)
Ad N

1
@AdN : 더 이상 표현식이 아니라 선언입니다.
Xeo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.