2011-05-20 40 views
16
template <typename TAG> 
fn(int left, TAG, int right) 
{ 
} 

fn(0, some_type_tag(), 1); 
/* or */ 
fn(0,int(), 1); // where the primitive, int, is not empty. 

EDIT: Có hai quan điểm cho câu hỏi này.Tham số chưa được đặt tên có thực sự được chuyển trong khi gọi hàm không?

  1. Tuyên bố chức năng so với định nghĩa. Việc khai báo có thể không đặt tên cho tham số, nhưng khai báo có thể làm. Đây không phải là quan điểm của sự quan tâm.
  2. Mẫu quan sát, phổ biến trong lập trình meta. Các tham số Trong câu hỏi là một thẻ được sử dụng để kéo ra một cấu trúc meta ra khỏi một đặc điểm. Đây là lý do tại sao tham số không được đặt tên, tôi chỉ quan tâm đến thông tin biên dịch - loại thẻ.

/EDIT

My tags thường rỗng-cấu trúc, tuy nhiên trong một số phần của mã của tôi họ typedefs của types.So nguyên thủy, tôi quan tâm để biết nếu trình biên dịch hiện đại sẽ thực sự vượt qua một tham số. Điều này có hai khía cạnh.

  1. Định kích thước ngăn xếp, có tính đến kích thước của loại thông số chưa đặt tên.
  2. Thực sự xây dựng ngăn xếp với giá trị được truyền.

Hãy giữ nó cho gcc 4.5 và MSVC 2008+

+1

Kết quả sẽ khác nhau tùy theo trình biên dịch và mức tối ưu. Bạn sẽ phải thử nó. –

+0

Tôi có 10 câu hỏi như thế này mỗi ngày, nếu tôi thử nghiệm mọi thứ tôi sẽ không nhận được bất kỳ công việc nào được thực hiện;), tôi đã đủ điều kiện cho câu hỏi với hai trình biên dịch mà tôi quan tâm. –

+2

@Hassan: Tôi nghĩ bạn sẽ đã kết thúc trước khi viết một bài kiểm tra đơn giản thay vì viết toàn bộ câu hỏi :) –

Trả lời

6

Đó thực sự là một câu hỏi thú vị. Trước hết, lưu ý rằng chúng ta đang ở một ngôn ngữ bắt buộc, có nghĩa là khi bạn yêu cầu một thứ gì đó (thậm chí vô ích, chẳng hạn như xây dựng một đối tượng không sử dụng) thì trình biên dịch cần tuân thủ trừ khi nó có thể xuất hiện với một biểu mẫu tương đương. . Về cơ bản, nó có thể bỏ qua các tham số nếu nó có thể chứng minh rằng làm như vậy sẽ không thay đổi ý nghĩa của chương trình.

Khi bạn viết một lời gọi hàm, có hai điều có thể xảy ra (cuối cùng):

  • hoặc nó được inlined
  • hoặc một call là thực sự phát ra

Nếu đó là inline, sau đó không có tham số nào được truyền, có nghĩa là các đối tượng không sử dụng có thể được gỡ bỏ (và thậm chí không được xây dựng) nếu trình biên dịch có thể chứng minh rằng các nhà xây dựng và destructors tham gia không thực hiện bất kỳ điều gì t làm việc. Nó hoạt động tốt cho các cấu trúc thẻ.

Khi cuộc gọi được phát ra, nó được phát ra với một quy ước gọi cụ thể. Mỗi trình biên dịch có tập hợp các quy ước gọi riêng của nó, chỉ định cách vượt qua các đối số khác nhau (this con trỏ, v.v ...), thường cố gắng tận dụng lợi thế của các thanh ghi có sẵn.

Vì chỉ có khai báo của hàm được sử dụng để xác định quy ước gọi (model biên soạn riêng), sau đó nó là cần thiết để thực sự vượt qua các đối tượng ...

Tuy nhiên, nếu chúng ta đang nói về một cấu trúc rỗng , không có phương pháp và không có trạng thái, thì đây chỉ là một số bộ nhớ chưa được khởi tạo. Nó không nên chi phí nhiều, nhưng nó đòi hỏi không gian ngăn xếp (ít nhất, đặt nó).

Demo sử dụng tryout llvm:

struct tag {}; 

inline int useless(int i, tag) { return i; } 

void use(tag); 

int main() { 
    use(tag()); 
    return useless(0, tag()); 
} 

Cung cấp:

%struct.tag = type <{ i8 }> 

define i32 @main() { 
entry: 
    ; allocate space on the stack for `tag` 
    %0 = alloca %struct.tag, align 8    ; <%struct.tag*> [#uses=2] 

    ; get %0 address 
    %1 = getelementptr inbounds %struct.tag* %0, i64 0, i32 0 ; <i8*> [#uses=1] 

    ; 0 initialize the space used for %0 
    store i8 0, i8* %1, align 8 

    ; call the use function and pass %0 by value 
    call void @_Z3use3tag(%struct.tag* byval %0) 
    ret i32 0 
} 

declare void @_Z3use3tag(%struct.tag* byval) 

Lưu ý:

  • lời mời gọi làm useless đã được gỡ bỏ, và không có lý lẽ được xây dựng cho nó
  • cách gọi tới use không thể bị xóa và do đó khoảng trống được phân bổ tạm thời (tôi hy vọng rằng các phiên bản mới không 0-khởi tạo bộ nhớ)
+0

Chỉ đúng mức độ phong cách, quyền lực và giai điệu tôi đang tìm kiếm: D –

+0

@ Hassan: Tôi đang học nhiều như bạn và tôi được biết là có sự mất tập trung, vì vậy nó chắc chắn là có thẩm quyền^^ –

2

Tốt câu hỏi, nhưng bạn sẽ phải thử trên trình biên dịch của bạn. Về lý thuyết, nếu một tham số không được sử dụng, nó không phải được phân bổ trong ngăn xếp. Tuy nhiên, người gọi phải biết làm thế nào để gọi nó, vì vậy tôi đoán là các yếu tố được thực sự được phân bổ trong ngăn xếp.

12

C++ có bản dịch riêng. Vì tham số có thể được đặt tên trong khai báo nhưng không có trong định nghĩa hàm và ngược lại, thường không có cách nào trình biên dịch biết liệu nó có an toàn để bỏ qua đối số hàm hay không. Khi tất cả trong cùng một đơn vị dịch, mọi thứ có thể được gạch chân và tên đối số hoàn toàn không liên quan đến tối ưu hóa.

[Added]

Bản dịch riêng biệt có thể không quan trọng đối với trường hợp cụ thể này, nhưng một người thợ xây biên dịch sẽ làm tăng thêm tối ưu hóa như vậy phải chăm sóc. Họ sẽ không đưa vào tối ưu hóa như vậy nếu nó phá vỡ mã hoàn toàn hợp lệ. Đối với các mẫu, cần thiết loại chức năng mẫu tương đương với loại hàm không phải mẫu, nếu không thì không thể lấy địa chỉ của nó và gán nó cho một con trỏ hàm. Một lần nữa, bạn phải đưa vào tài khoản dịch riêng biệt. Chỉ vì bạn không có địa chỉ của foo<int> trong TU này không có nghĩa là bạn sẽ không ở địa chỉ khác.

+1

+1 để dịch riêng biệt – sehe

+0

Trình biên dịch tạo ra một cuộc gọi hàm nếu một địa chỉ được thực hiện. Tuy nhiên, nó sẽ không (hoặc không nên) sử dụng chức năng mới này trừ khi nó phải. vẫn còn lại lớp chức năng đang được giám sát trong trường hợp sử dụng của tôi = D. Vì vậy, có lẽ chúng ta có thể giả định rằng nếu một địa chỉ được thực hiện, trình biên dịch sẽ tạo ra một cú gọi gọi hàm tham gia tham số thẻ vào tài khoản. –

+0

Điều đó vẫn còn để lại một vấn đề: nếu người gọi _one_ lấy thông số vào tài khoản, thì callee phải, điều này có nghĩa là người gọi _all_ phải. – MSalters

7

Cho dù tham số được đặt tên hay không có ảnh hưởng đến chữ ký hàm và trình biên dịch sẽ chuyển nó vào. Hãy xem xét tham số chưa đặt tên trong khai báo hàm có thể được đặt tên trong định nghĩa.

Bây giờ, trong trường hợp cụ thể của các mẫu như trên, rất có thể trình biên dịch sẽ nội tuyến mã, trong trường hợp không có đối số nào được chuyển, và đối số chưa đặt tên sẽ không có hiệu lực.

Nếu những gì bạn đang cố gắng làm là gắn thẻ để giải quyết các tình trạng quá tải khác nhau, bạn luôn có thể quay trở lại con trỏ, để ngay cả khi nó được truyền vào, chi phí sẽ tối thiểu.

+0

+1 cho hàm ý nội tuyến – sehe

+0

cảm ơn Tôi thực sự quan tâm đến phối cảnh mẫu. Tôi đã đủ điều kiện để hỏi thêm về điều này. Nói chung là tôi có thể sử dụng các kiểu nguyên thủy như các thẻ, thay vì các cấu trúc rỗng, kích thước trên không phải là xấu, nếu tôi sử dụng con trỏ, tôi sẽ trả chi phí 8 byte cho mã 64 bit mọi lúc: D. Mặc dù 8-byte của không gian callstack thực tế không có tác động đến hiệu suất tôi đoán. –

+0

@Hassan Syed: Nếu bạn sử dụng 64 bit, rất có thể quy ước gọi là sử dụng rộng rãi thanh ghi, điều này sẽ có nghĩa là đối với bất kỳ thứ gì phù hợp với thanh ghi, chi phí sẽ là của nó.) –

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