2015-09-23 21 views
7

Tôi đã được đánh răng lên trên khái niệm mảng trong C++, khi tôi đi qua câu hỏi này: Return an array in c++Cú pháp trả lại một tham chiếu mảng trong C++

Có người đã trả lời bằng lời tuyên bố này:

int (&f(int (&arr)[3]))[3] 

Những gì tôi có thể dường như không nắm bắt được [3] sau khi đóng ngoặc đơn. Tôi chưa bao giờ nhìn thấy một tuyên bố chức năng trông như thế này. Tôi hiểu phần còn lại của cú pháp, nhưng tôi không đặc biệt hiểu cách [3] hoạt động vì nó là sau tên hàm. Tôi xin lỗi trước nếu tôi nhìn thấy một cái gì đó đơn giản. Tôi cũng đã thử nhìn vào spec cho khai báo chức năng nhưng tôi không thấy bất cứ điều gì liên quan mà tôi có thể liên kết đến cú pháp subscript. Vậy làm thế nào có thể như vậy?

+1

Bởi vì K & R là kẻ tàn ác . – orlp

+0

http://cdecl.org/. Cú pháp khai báo C có thể là "vui". –

+1

Một khi bạn nhận được nó, xin vui lòng không bao giờ bao giờ viết điều khủng khiếp như vậy trong một mã đời thực. – kebs

Trả lời

5

Chức năng này trả về một tài liệu tham khảo tới một mảng của int kích thước 3[3] phần sau khi chức năng thực sự là kích thước của mảng được trả về như tham khảo.

cú pháp che khuất này xuất phát từ cú pháp lạ của khai báo mảng, mà bạn làm như sau:

int arr[3]; //real but weird 

Ngôn ngữ có thể đã được đơn giản hơn nhiều nếu nó có này để thay thế:

int[3] arr; //hypothetical but better and simpler 

vì kích thước 3một phần của loại arr, do đó, điều này có ý nghĩa hơn nếu tất cả các phần xuất hiện ở phía bên trái của tên biến, giống như cách bạn viết:

unsigned int a; 

Bạn không ghi:

unsigned a int; //analogous to : int a [3]; 

Vì vậy, trong khi ngôn ngữ làm điều đúng với unsigned int, nó là một điều rất lạ với int[3].

Bây giờ trở lại với phần khai báo hàm, chức năng sẽ tốt hơn nhiều nếu nó được khai báo là:

int[3]& f(int[3]& arr); //hypothetical 

chỉ khi nó đã có tất cả các bộ phận trên bên trái của biến-name. Nhưng vì nó không làm điều đó (tức là ngôn ngữ đòi hỏi bạn để ghi các kích thước ở phía ngoài cùng bên phải sau tên biến), bạn kết thúc với chữ ký kỳ lạ này:

int (&f(int (&arr)[3])[3]; //real 

Chú ý rằng ngay cả những cách tham số trở nên kỳ lạ.


Nhưng bạn có thể đơn giản hóa nó với một typedef như:

typedef int array_type[3]; 

array_type& f(array_type& arr); 

Điều đó có vẻ tốt hơn nhiều. Bây giờ chỉ có typedef có vẻ lạ.

Với C++ 11, bạn có thể viết ngay cả một typedef tốt hơn:

using array_type = int[3]; 

array_type& f(array_type& arr); 

đó là càng gần càng này (nếu bạn hình dung array_type như int[3]):

int[3]& f(int[3]& arr); //hypothetical 

Hy vọng rằng sẽ giúp .

+1

Cảm ơn rất nhiều! Điều này tất cả có ý nghĩa bây giờ. – Izodine

1
int (&f (int (&arr)[3]))[3] 
{ 
    return arr; 
} 

Hãy đi từ bên trong. Phần (int (&arr)[3]) có nghĩa là hàm lấy tham chiếu đến một mảng int gồm 3 phần tử làm tham số. Đây là cùng một arr đang được trả lại.

Bây giờ, phần còn lại của cú pháp sai rằng hàm sẽ trả về tham chiếu đến một mảng gồm 3 int. f là tên của hàm. int &f() có nghĩa là bạn trả về tham chiếu đến int, nhưng bạn cần phải trả về một mảng có kích thước cố định, do đó bạn nên thêm [3] Dấu ngoặc đơn xung quanh &f(...) được sử dụng vì trong C++ bạn ghi kích thước của mảng sau biến tên, không phải sau tên loại, như Nawaz giải thích trong câu trả lời của mình. Nếu bạn bỏ qua các dấu ngoặc đơn đó, trình biên dịch sẽ giải thích f dưới dạng một mảng tham chiếu, như trong int & f[3].

2

Vâng, hãy đọc article về lịch sử C này, bởi người sáng tạo Dennis M. Ritchie.

Hình như cú pháp này, chúng tôi nhận được từ B, qua C đến C++ ...

Tôi tin rằng, bằng cách này để bày tỏ ý một số biến của một số "loại cơ bản" là cội rễ cú pháp kỳ lạ này:

int a, *b, c[3]; 

Vì vậy a chỉ int là, b là con trỏ đến intc là mảng của int ...

Nếu những *[3] sẽ là một phần của định nghĩa kiểu không phải là một biến định nghĩa - thì chúng ta sẽ cần 3 dòng viết này:


Có hai nguồn lực tốt về SO C page để học cách phân tích công trình xây dựng như:

cdecl là không một chút - vì tài liệu tham khảo không phải là một phần của C - vì vậy hãy thử với The Clockwise/Spiral Rule for parsing C declarations.

int (&f(int (&arr)[3]))[3] 
  1. arr -> arr
  2. &arr -> arr là tham khảo
  3. (&arr) -> arr là tham chiếu - xung quanh () không thực sự thay đổi một điều
  4. (&arr)[3] -> arr là tham chiếu đến mảng có kích thước 3
  5. int (&arr)[3] -> arr là tham chiếu đến mảng có kích thước 3 kiểu int

Tiếp theo:

  1. f -> f
  2. f(int (&arr)[3]) -> f là chức năng lấy arr, đó là ...
  3. &f(int (&arr)[3]) -> f là hàm lấy arr, là ..., và trả về tham chiếu
  4. (&f(int (&arr)[3]))[3] -> f là hàm lấy arr, là ... và trả về tham chiếu đến mảng có kích thước 3
  5. int (&f(int (&arr)[3]))[3] -> f là hàm lấy arr, tham chiếu đến mảng có kích thước 3 của kiểu int, và trở về tham chiếu đến mảng có kích thước 3 kiểu int

Tất nhiên - mã này sẽ được thay thế bằng, ít nhất là đối với tôi, dễ dàng hơn để đọc phiên bản:

using int3 = int[3]; 
int3& f(int3& arr); 
+0

Điều này có ý nghĩa. Cảm ơn các câu trả lời chi tiết! Quy tắc xoắn ốc sẽ rất hữu ích. – Izodine

Các vấn đề liên quan