Tôi không hiểu tại sao điều này biên dịch


80

Tôi chắc chắn thiếu một cái gì đó, nhưng tôi không hiểu tại sao điều này biên dịch (với cả g ++ & clang ++):

struct A
{
};
struct B
{
};

int main()
{
  A a(B);
}

Trước hết, Blà một loại ... không phải là một giá trị. Làm thế nào tôi nên giải thích mã này?


37
Điều này được gọi là Parse gây phiền nhiễu nhất
thay đổi igel

8
@alterigel Có thật không? Trong trường hợp này không có sự mơ hồ. Nó chỉ có thể là một khai báo chức năng. Nó không phải A a(B());là một định nghĩa biến hoặc khai báo hàm.
quả óc chó

8
Bạn sẽ ngạc nhiên khi biết rằng struct A{}; int main() { A(foo); } biên dịch như vậy , ngay cả khi fookhông đặt tên gì.
Ayxan

20
@alterigel - đây không phải là phân tích khó chịu nhất. Nhìn vào các ví dụ trên trang mà bạn liên kết đến. Đây chỉ đơn giản là một khai báo chức năng.
Pete Becker

3
@PeteBecker, có thể tốt hơn để giải thích tại sao đây không phải là MVP thay vì chỉ khẳng định rằng nó không phải, điều mà tôi tin rằng quả óc chó đã làm ở trên.
JPhi1618

Câu trả lời:


84

Nó được hiểu là khai báo của một hàm có tên a, lấy một đối số kiểu Bvà trả về A.


5
Và đó là lý do tại sao nó là nhất và làm phiền. Một giải pháp: (không phải là nó thực sự giải quyết được bất cứ điều gì vì nó phơi bày công trình xấu)A a{B};
user4581602

23
@ user4581301 - đây không phải là phân tích khó chịu nhất. Nó chỉ đơn giản là một khai báo hàm.
Pete Becker

23
Vì vậy, hóa ra nó chỉ là một phân tích chủ yếu gây phiền
toái

11
Phần kỳ lạ nhất của nó là C ++ không cho phép các hàm lồng nhau, nhưng không cho phép khai báo bên trong một hàm.
The_Sympathizer

6
Âm thanh như một động lực tốt để thêm hỗ trợ cho các chức năng lồng nhau vào C ++; chúng không chỉ hữu ích, mà còn biến cái mụn cóc kỳ quặc này thành một thiết kế hợp lý :)
Jeremy Friesner

15

Nó chỉ đơn giản là một khai báo hàm khai báo alà một hàm trả về Avà lấy một tham số không tên của loại B.

Nó là hợp lệ vì khai báo hàm trái với định nghĩa hàm được cho phép trong các định nghĩa hàm.


13

Vấn đề này được gọi là phân tích vexing nhất . Dòng này A a(B);có thể được hiểu là khai báo của một hàm có tên atrả về một đối tượng kiểu Avà lấy tham số không tên của loại B.

Một cách để tránh vấn đề này là sử dụng cú pháp khởi tạo thống nhất được giới thiệu trong C ++ 11, bao gồm sử dụng dấu ngoặc thay vì dấu ngoặc đơn: A a{B};trả về lỗi. Dòng này hiện được hiểu là một khai báo biến được khởi tạo với B, đây là một loại thay vì một giá trị.

Đây là thông tin thêm:

Phân tích khó chịu nhất: Cách phát hiện và khắc phục nhanh chóng


12
Tôi không nghĩ rằng điều này nên được gọi là " phân tích cú pháp nhất ". Nó chỉ là một khai báo hàm thông thường vì nó cũng tồn tại trong C. Không có độ phân giải mơ hồ cần thiết vì dòng chỉ có thể là một khai báo hàm, không có gì khác. Nhìn vào liên kết của bạn. Các ví dụ đều khác nhau từ điều này.
quả óc chó

3
Trong khi đó là sự thật, nó có liên quan đến phân tích bực tức nhất. Chỉ là điều này cũng bao gồm một lỗi đánh máy trong đó một tên loại được sử dụng một mình thay vì một lệnh gọi hoặc hàm tạo, như có lẽ là mục đích ban đầu.
Miral

1
Vâng, "Hầu hết các phân tích vexing" là một câu trả lời hữu ích trong trường hợp này, mặc dù trường hợp thực tế trong câu hỏi chỉ là "Phân tích cú pháp hơi khó hiểu".
jpa

1
@wlanut: Các cấu trúc trống struct A { };không hợp lệ trong tiêu chuẩn C, ngay cả khi một số trình biên dịch cho phép chúng. Thả niềng răng và sẽ không có vấn đề ở đó. Ngoài ra, trong C, khai báo hoặc định nghĩa struct Akhông tạo tên loại A(bạn phải thêm tiền tố vào structhoặc thêm vào typedef struct A A;đâu đó trước khi Ađược sử dụng mà không có structtiền tố). Ngoài ra trong C, không có phân tích cú pháp thay thế nào cho khai báo hàm - sử dụng type name(...);đơn giản không bao giờ có thể là một định nghĩa biến; nó luôn luôn là một khai báo hàm (hoặc không hợp lệ). Mã trong câu hỏi không hợp lệ trong C.
Jonathan Leffler
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.