2011-11-01 56 views
22

Các mã sau đây trả về kích thước của một mảng đống phân bổ:Mã C++ này có nghĩa là gì?

template<typename T, int size> 
int siz(T (&) [size]) 
{ 
    return size; 
} 

nhưng tôi không thể quấn quanh đầu tôi cú pháp. Đặc biệt là phần T (&) [size] ...

+1

bản sao có thể có của [Tại sao "tham chiếu đến mảng" được xác định theo cách gây nhầm lẫn trong C++?] (Http://stackoverflow.com/questions/6456253/why-is-reference-to-array-defined-in- như vậy khó hiểu-way-in-c) – sharptooth

+7

không hoàn toàn trùng lặp –

+0

Bạn có thể muốn sử dụng một mẫu bí danh và viết 'bí danh &' có thể dễ đọc hơn. –

Trả lời

24

nhưng tôi không thể che giấu xung quanh cú pháp. Đặc biệt là phần T (&) [size] ...

Phần đó là tham chiếu đến một mảng. Có "right-left rule" để giải mã mọi khai báo C và C++ .

Bởi vì các mẫu chức năng suy ra các loại đối số mẫu từ các đối số hàm được cung cấp những gì mẫu chức năng này làm là suy ra loại và phần tử đếm của mảng và trả về số đếm.

Chức năng không thể chấp nhận loại mảng theo giá trị, thay vì chỉ bằng con trỏ hoặc tham chiếu. Các tài liệu tham khảo được sử dụng để tránh việc chuyển đổi tiềm ẩn của một mảng để con trỏ tới phần tử đầu tiên của mình (aka, phân rã mảng):

void foo(int*); 

int x[10]; 
int* p = x; // array decay 
foo(x);  // array decay again 

Mảng phân rã phá hủy các loại ban đầu của mảng và do đó kích thước của nó bị mất .

Lưu ý, vì đó là cuộc gọi hàm trong C++ 03, giá trị trả về không phải là hằng số thời gian biên dịch (tức là không thể sử dụng giá trị trả về làm đối số mẫu). Trong C++ 11 chức năng có thể được đánh dấu bằng constexpr trở lại trong một thời gian liên tục biên dịch:

template<typename T, size_t size> 
constexpr size_t siz(T(&)[size]) { return size; } 

Để có được phần tử mảng được tính là một thời gian biên dịch liên tục trong C++ 03 một hình thức hơi khác nhau có thể được sử dụng:

template<class T, size_t size> 
char(&siz(T(&)[size]))[size]; // no definition required 

int main() 
{ 
    int x[10]; 
    cout << sizeof siz(x) << '\n'; 
    double y[sizeof siz(x)]; // use as a compile time constant 10 
} 

Ở phía trên nó tuyên bố một hàm mẫu với lập luận tương tự tham khảo-to-an-mảng, nhưng với kiểu giá trị trở lại của char(&)[size] (đây là nơi "quy tắc phải trái" có thể được đánh giá cao) . Lưu ý rằng các cuộc gọi chức năng không bao giờ xảy ra tại thời gian chạy, đây là lý do tại sao định nghĩa của mẫu chức năng siz là không cần thiết. sizeof siz(x) về cơ bản là nói số "kích thước của giá trị trả lại là bao nhiêu nếu siz(x) được gọi là".

C/C++ cách cũ nhận được số lượng phần tử của mảng như một thời gian biên dịch liên tục là:

#define SIZ(arr) (sizeof(arr)/sizeof(*(arr))) 
+0

là các parens xung quanh & cần thiết? –

+0

@JasonS - các dấu ngoặc kép được yêu cầu để tránh trông giống như một mảng tham chiếu đến 'T' – Flexo

+0

ah, ok ... và' (T &) [size] 'sẽ không hoạt động? (xin lỗi, không có trình biên dịch C và chạy) –

4

Nó rất một chức năng mà trở thành một typename (mẫu có thể được sử dụng với typenames khác nhau) và kích thước từ bên ngoài. Sau đó nó trả về kích thước này.

Chức năng ngăn xếp thường sử dụng size, là số nguyên cho biết kích thước của kích thước ngăn xếp mà bạn yêu cầu với hàm này. Các thử nghiệm & chỉ có kích thước của ngăn xếp T có nghĩa là.

7

T (&) [size] là tham chiếu đến một mảng.Nó cần phải là một tài liệu tham khảo vì chương trình sau đây là không hợp pháp:

#include <iostream> 

int sz(int *) { std::cout << "wtf?" << std::endl; return 0; } 


int sz(int [4]) { std::cout << "4" << std::endl; return 0; } 

int main() { 
    int test[4]; 
    sz(test); 
} 

Chương trình này thất bại trong việc biên dịch với:

test.cc: In function ‘int sz(int*)’: 
test.cc:6:5: error: redefinition of ‘int sz(int*)’ 
test.cc:3:5: error: ‘int sz(int*)’ previously defined here 

int sz(int [4]) giống hệt int sz(int *).

Dấu ngoặc đơn được yêu cầu phân biệt ở đây vì T& [size] trông giống như một mảng tham chiếu không hợp pháp.

Thông thường nếu tham số không phải là vô danh bạn sẽ viết:

template<typename T, int size> 
int sz(T (&arr) [size]) 

Để cung cấp cho mảng tên arr. Trong trường hợp này, mặc dù tất cả mã ví dụ của bạn được quan tâm là kích thước được suy luận và do đó đối số ẩn danh tránh các cảnh báo về các đối số không được sử dụng.

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