Làm thế nào là int int int () {(([] () {}) ());} CQ hợp lệ?


271

Gần đây tôi đã đi qua đoạn mã bí truyền sau đây.

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

Định dạng lại nó như sau để dễ đọc hơn:

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

Nhưng tôi không thể hiểu được (([](){})())mã hợp lệ như thế nào .

  • Nó không giống như cú pháp con trỏ hàm.
  • Nó không thể là một số thủ thuật quá tải nhà điều hành. Mã biên dịch như là.

Google đã không giúp nhiều cho việc tìm kiếm tất cả các biểu tượng này. Nhưng nó biên dịch trong Visual Studio 2010 và không cho ra kết quả gì. Không có lỗi, và không có cảnh báo. Vì vậy, nó trông giống như mã hợp lệ.

Tôi chưa từng thấy bất kỳ mã hợp lệ mà là bên ngoài rất kỳ lạ của JavascriptC con trỏ hàm .

Ai đó có thể giải thích làm thế nào điều này là C ++ hợp lệ?


94
Chào! Đó là của tôi. "Don't sweat it. We have int main(){(([](){})());} which is valid C++" (Ngày 9 tháng 11 trong trò chuyện)
sehe

31
đó là một đóng cửa lambda c ++ 11

7
@Mysticial - Mã này làm bạn bối rối vì nó vô dụng. Nếu lambda này sẽ làm một cái gì đó, bạn sẽ nhận ra nó có cú pháp tương tự như con trỏ hàm (với nó có liên quan chặt chẽ).
SChepurin

14
@Mysticial - "6 năm của C ++" - lambdas mới được thêm vào C ++ 11, vì vậy không ai có kinh nghiệm với họ trước đó một năm.
Pete Becker

50
URL ở đây khá thú vị: "how-is-int-main-valid-c"
tckmn

Câu trả lời:


283

Mã về cơ bản gọi một lambda trống.

Hãy bắt đầu lại từ đầu: [](){}là một biểu thức lambda trống rỗng .

Sau đó, trong C và C ++, bạn có thể gói các biểu thức trong parens và chúng hoạt động giống hệt nhau như thể được viết mà không có chúng, vì vậy đó là những cặp parens đầu tiên xung quanh lambda. Bây giờ chúng ta đang ở ([](){}).

Sau đó, ()sau khi các gói đầu tiên gọi lambda (trống). Chúng tôi đang ở([](){})()

Toàn bộ biểu thức được bọc trong parens một lần nữa và chúng tôi nhận được (([](){})()).

Cuối cùng, ;kết thúc tuyên bố. Chúng tôi đến nơi (([](){})());.


một số trường hợp góc ít nhất là trong C ++, như T a_var; có sự khác biệt giữa decltype(a_var)decltype((a_var)) .


7
Bỏ lỡ một con dao găm.
R. Martinho Fernandes

33
@ R.MartinhoFernandes: Nó vẫn bị mắc kẹt trong một ai đó, vì vậy tôi phải đi lấy nó.
Xèo

1
Tôi sẽ upvote vì đã đề cập chính xác đến trường hợp thêm () xung quanh một biểu thức làm thay đổi ngữ nghĩa. Nhưng sau đó tôi nhớ rằng không có liên quan đến câu hỏi, thực sự. Câu trả lời hay
sehe

2
Các dấu ngoặc đơn cũng đang thay đổi ý nghĩa của một chương trình trong trường hợp định nghĩa phân tích cú pháp khó hiểu nhất: B foo(A())foo là một hàm (lấy một con trỏ để chỉ làm tham số và trả về B) trong khi trong B foo((A()))foo là một đối tượng B được xây dựng gọi một hàm tạo một đối tượng (trường hợp này là tạm thời ẩn danh trong trường hợp này).
Quảng cáo N

1
@AdN: Đó không phải là một biểu thức nữa, mà là một tuyên bố.
Xèo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.