Tại sao C ++ lại cho phép chúng ta đặt tên biến trong dấu ngoặc đơn khi khai báo một biến?


84

Ví dụ một khai báo như sau:

int (x) = 0;

Hoặc thậm chí rằng:

int (((x))) = 0;

Tôi tình cờ gặp phải điều này vì trong mã của tôi, tôi đã tình cờ có một đoạn tương tự như đoạn sau:

struct B
{
};

struct C
{
  C (B *) {}
  void f () {};
};

int main()
{
  B *y;
  C (y);
}

Rõ ràng là tôi muốn xây dựng đối tượng Cmà sau đó sẽ làm điều gì đó hữu ích trong trình hủy của nó. Tuy nhiên, khi nó xảy ra, trình biên dịch coi C (y);như một khai báo của biến ycó kiểu Cvà do đó nó in ra lỗi về yđịnh nghĩa lại. Điều thú vị là nếu tôi viết nó như C (y).f ()hoặc một cái gì đó giống như C (static_cast<B*> (y))nó sẽ biên dịch như dự định. Tất nhiên, giải pháp hiện đại tốt nhất là sử dụng {}trong lệnh gọi hàm tạo.

Vì vậy, như tôi đã tìm ra sau đó, có thể khai báo các biến như int (x) = 0;hoặc thậm chí int (((x))) = 0;nhưng tôi chưa bao giờ thấy ai thực sự sử dụng các khai báo như thế này. Vì vậy, tôi quan tâm - mục đích của khả năng như vậy là gì bởi vì hiện tại tôi thấy rằng nó chỉ tạo ra trường hợp tương tự như "phân tích cú pháp khó chịu nhất" khét tiếng và không thêm bất cứ điều gì hữu ích?


"Mục đích" của khả năng có thể là để đơn giản hóa trình phân tích cú pháp.
molbdnilo


1
@GSerg Buồn cười làm sao văn bản câu hỏi của tôi trả lời cho câu hỏi từ câu trả lời thứ hai trong câu hỏi được liên kết của bạn, vì tôi cung cấp ví dụ mà việc cho phép khai báo như vậy dẫn đến kết quả không mong muốn :)
Predelnik


bước vào cái bẫy này: không biết mutex đã được nhận xét ra và sau đó vô tình viết khai báo dấu ngoặc đơn không chính xác. // std :: mutex std :: unique_lock <std :: mutex> (m_mutex);
Phục vụ Laurijssen

Câu trả lời:


80

Phân nhóm.

Như một ví dụ cụ thể, hãy xem xét rằng bạn có thể khai báo một biến kiểu hàm như

int f(int);

Bây giờ, làm thế nào bạn sẽ khai báo một con trỏ đến một thứ như vậy?

int *f(int);

Không, không hoạt động! Đây được hiểu là một hàm trả về int*. Bạn cần thêm vào trong dấu ngoặc đơn để phân tích cú pháp đúng cách:

int (*f)(int);

Tương tự với các mảng:

int *x[5];   // array of five int*
int (*x)[5]; // pointer to array of five int

13
Và để hoàn thành câu trả lời: không cho phép trường hợp cụ thể mà người hỏi đang hỏi sẽ yêu cầu một quy tắc trường hợp đặc biệt bổ sung. Định nghĩa hiện tại về cách thức ()hoạt động trong một kiểu là thống nhất trong cả kiểu.
Joseph Mansfield

Vì vậy, trường hợp đặc biệt áp dụng cho phân tích cú pháp khó chịu nhất. Điều này là do cú pháp để khởi tạo các biến với các đối số hàm tạo đã được thêm vào sau đó (tôi đoán là do vội vàng?).
AnArrayOfFunctions

1
@FISOCPP Chà. . Đúng. C ++ đứng sau C. .
iheanyi

Câu trả lời này có áp dụng như nhau cho C, không chỉ C ++ không?
kdbanman

" biến kiểu hàm " gì? !!
curiousguy

17

Thường được phép sử dụng dấu ngoặc đơn trong các khai báo như vậy vì khai báo, từ quan điểm cú pháp trông luôn như thế này:

<front type> <specification>;

Ví dụ, trong khai báo sau:

int* p[2];

"Loại phía trước" là int(không phải int*) và "đặc điểm kỹ thuật" là * p[2].

Quy tắc là bạn có thể sử dụng bất kỳ số lượng dấu ngoặc nào nếu cần trong phần "đặc tả" vì chúng đôi khi không thể tránh khỏi việc phân biệt. Ví dụ:

int* p[2]; // array of 2 pointers to int; same as int (*p[2]);
int (*p)[2]; // pointer to an array of 2 ints

Con trỏ tới một mảng là một trường hợp hiếm gặp, tuy nhiên, bạn cũng gặp phải trường hợp tương tự với con trỏ tới hàm:

int (*func(int)); // declares a function returning int*
int (*func)(int); // declares a pointer to function returning int

Đây là câu trả lời trực tiếp cho câu hỏi của bạn. Nếu câu hỏi của bạn là về tuyên bố như thế C(y), thì:

  • Đặt dấu ngoặc đơn xung quanh toàn bộ biểu thức - (C(y))và bạn sẽ nhận được những gì bạn muốn
  • Câu lệnh này không làm gì khác ngoài việc tạo một đối tượng tạm thời, đối tượng này sẽ ngừng hoạt động sau khi hướng dẫn này kết thúc (tôi hy vọng đây là những gì bạn dự định làm).

1
Như tôi đã đề cập, ban đầu nó đang thực hiện một cái gì đó trong hàm hủy, tôi đoán đó là điều khá chuẩn khi bạn có một số hàm "chuỗi" để thiết lập một số tham số và sau đó thực hiện tất cả công việc trong bộ hủy. Mặc dù vậy, cảm ơn vì một giải pháp nữa, tôi nghĩ rằng viết lách {}là cách giải quyết hợp lý nhất sau tất cả.
Predelnik

4
cố gắng tránh tạo ra ngữ pháp của riêng bạn và sử dụng ngữ pháp được cung cấp trong tiêu chuẩn. <front-type> <specification>là sai lệch, và sai. Ngữ pháp là<declaration-specifier> <declarator>
Steve Cox

Bạn nói đúng - Tôi đã không xem xét tiêu chuẩn, chỉ lặp lại quy tắc từ đầu. Trên thực tế trong C ++ 11, vai trò của <declaration-specifier>cũng có thể được thực hiện bởi autotừ khóa, vì vậy nó thậm chí không phải lúc nào cũng là một kiểu.
Ethouris

@Pravasi Meet: Nếu bạn đã chỉnh sửa phần bài đăng của tôi và thay đổi tên trong lược đồ cú pháp đã cho, vui lòng thay đổi tên 3 dòng bên dưới cho phù hợp. Nếu không thì vẫn có những tên cũ "loại mặt trước" và "đặc điểm kỹ thuật" và do đó bài đăng không có ý nghĩa gì.
Ethouris
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.