2016-02-29 16 views
42

Tôi đang sử dụng để khai báo chức năng variadic như thế này:Comma bỏ qua trong khai báo hàm variadic trong C++

int f(int n, ...); 

Khi đọc C++ Programming Language tôi thấy rằng các tuyên bố trong cuốn sách bỏ qua các dấu phẩy:

int f(int n...); // the comma has been omitted 

nó có vẻ như cú pháp này là C++ cụ thể như tôi nhận được lỗi này khi tôi cố gắng để biên dịch nó sử dụng một trình biên dịch C:

test.c:1:12: error: expected ‘;’, ‘,’ or ‘)’ before ‘...’ token int f(int n...);

Có sự khác biệt giữa văn int f(int n, ...)int f(int n...)?

Tại sao cú pháp này được thêm C++?

+2

http://en.cppreference.com/w/cpp/utility/variadic – knivil

+1

[Tham chiếu khác] (http://en.cppreference.com/w/cpp/language/variadic_arguments) mô tả tính đặc thù này. Nhìn vào cuối trang về 'printz (...)'. – callyalater

+1

Tôi tin rằng tính năng này đã được thêm vào C++ vì * toán tử * bản chất của '...'. Điều này cho phép cú pháp nhất quán hơn trong ngôn ngữ với các tính năng được thêm vào như [tham số gói] (http://en.cppreference.com/w/cpp/language/parameter_pack). – callyalater

Trả lời

36

Theo § 8.3.5.4 của chuẩn C++ (current draft):

đâu đúng cú pháp và ở đâu “...” không phải là một phần của một bản tóm tắt -declarator “...” đồng nghĩa với "...".

Tóm lại, trong C++ ... (dấu ba chấm) là toán tử và có thể sử dụng mà không có dấu phẩy, nhưng việc sử dụng dấu phẩy được giữ lại để tương thích ngược.

+11

... và, theo quan điểm của tôi, cho rõ ràng. 'int n ...' trông giống như nó cần phải có một cái gì đó để làm với việc mở rộng gói tham số. Hoặc, ít nhất, có vẻ như '...' có liên quan đến 'n'. –

+0

@PreferenceBean Trong tất cả sự công bằng, nó có thể trước khi mở rộng gói tham số (C++ 11). – Pharap

+0

@Pharap: Nó 100% nhưng điều đó không thay đổi những gì tôi đã nói! –

15

Với int f(int n, ...);int f(int n...);, vì bạn có thể see, cả hai , ...... đều có cùng ý nghĩa. Dấu phẩy là tùy chọn.

Nhưng điều này int printz(...); hợp lệ trong C++ trong khi int printz(,...); không phải là (ít nhất một thông số được đặt tên phải xuất hiện trước thông số dấu ba chấm). Đó là lý do tại sao bạn có thể chỉ có (...), mặc dù các đối số được truyền cho chức năng như vậy không thể truy cập được.

29

Hiện nay, cả hai tuyên bố có cùng ý nghĩa:

int f(int n, ...); 
int f(int n ...); 

Điều này dẫn đến một vấn đề mà hai tờ khai sau đều quy phạm pháp luật, nhưng có ý nghĩa cực kỳ khác nhau:

template <class... T> void f(T...); // function template with parameter pack 
template <class T> void f(T...); // variadic function 

Khi C++ 11 giới thiệu các mẫu variadic, có nhiều khả năng tuyên bố thứ hai là lỗi lập trình hơn là bỏ qua dấu phẩy. Kết quả là, đã có một đề xuất để xóa ngôn ngữ thứ hai khỏi ngôn ngữ (P0281), nhưng rõ ràng là rejected.

+0

Rất thú vị cần lưu ý. Nhưng tôi không đồng ý với đặc điểm của bạn là "bỏ qua lười biếng". Không có nó * luôn luôn * là trường hợp bình thường. Một dấu phẩy thêm được định nghĩa là một từ đồng nghĩa, để tương thích với các khai báo C, hoặc có lẽ bạn thêm nó vào để trông đẹp hơn. Nhưng đó là một cái gì đó * thêm * không phải cái gì đó * bỏ qua *. –

+0

Đề xuất đã bị từ chối trong EWG vào thứ Ba. – Cubbi

+0

@Cubbi :: sad panda :: – Barry

6

Khi tôi nhớ lại từ thời điểm đó, C++ thực sự đã xác định ký hiệu hàm variadic như bạn lưu ý. Sau đó, ngôn ngữ C phát triển nhanh chóng (trên hành trình từ K & R đến ANSI) đã giới thiệu nguyên mẫu hoặc khai báo hàm kiểu mới cũng khai báo các tham số bên trong dấu ngoặc sau tên hàm.Nhưng, với hai sự khác biệt đáng chú ý: dấu phẩy trước dấu ba chấm và nhu cầu hủy bỏ (void) để biểu thị danh sách tham số trống (để giữ khả năng tương thích ngược của các dấu ngoặc đơn trống theo kiểu khai báo kiểu cũ).

Nhìn qua tài liệu lưu trữ của tôi, tôi tìm C++ Ngôn ngữ lập trình phiên bản gốc "in lại với sự điều chỉnh tháng 7 năm 1987" cho thấy:

        luận-khai-list:
                arg-declaration-list opt
... opt

        arg-khai-list:
              arg-khai-list
, luận-khai
              luận-khai

không có biểu mẫu để chấp nhận dấu phẩy hiện tại tùy chọn. Lưu ý rằng danh sách khai báo arg là một dấu phẩy- được tách riêng và điều này không treo để cung cấp dấu phẩy sau danh sách và trước điều tiếp theo (khác).

Đây là cách tự nhiên nhất để viết điều này. Nếu bạn muốn dấu phẩy, bạn cần rõ ràng , ... trong lần sản xuất đầu tiên, dưới dạng hai mã thông báo riêng biệt (có thể được phân tách bằng khoảng trắng).

Khi các nỗ lực của C đạt được tiêu chuẩn hóa phù hợp, trình biên dịch C++ bắt đầu chấp nhận các phiên bản C cũng như cho phép dễ dàng sử dụng các tệp tiêu đề C chuẩn.

Tại sao các nhà thiết kế C thêm dấu phẩy khi nó ngụ ý vai trò ngữ pháp ít hợp lý hơn của dấu ba chấm như một trình giữ chỗ tham số giả mạo? Tôi chưa bao giờ phát hiện ra.

+0

Vì vậy, lập luận của bạn là dấu phẩy là xấu bởi vì nó làm cho các quy tắc ngữ pháp [hơi] khó viết hơn? – Barry

+0

Không, đó không phải là điểm và quan sát chỉ ra rằng điểm bị thiếu. Nó giống như điểm tuyên bố: nó không bao giờ cần thiết và không được thiết kế. Vậy tại sao bạn cho rằng "bỏ nó ra" thậm chí là một điều? –