2011-08-18 34 views
8

Xin lỗi nếu điều này đã được yêu cầu trước đó, nhưng tôi không thể tìm thấy nó.chức năng truyền theo giá trị (?) Thay vì con trỏ hàm?

Vì vậy, tôi đang cố gắng tự học về mẫu và các tính năng C++ 11 mới (chủ yếu là lambdas, thứ mà tôi luôn thích bằng các ngôn ngữ khác).

Nhưng trong các thử nghiệm của tôi, tôi đã đến một cái gì đó tôi không hề biết nó làm việc, và tôi đang cố gắng để hiểu làm thế nào nó hoạt động nhưng không thể con số nó ra ..

Các mã sau đây:

template <class Func> 
void Test(Func callback) { 
    callback(3); 
} 

void Callback(int i) { 
    std::cout << i << std::endl; 
} 

int main(int argc, char** argv) { 
    Test(&Callback); // this I was expecting to work, compiler will see its a pointer to a function 
    Test(Callback); // this also works, but how?! 
    return 0; 
} 

Nếu tôi hiểu cách thức hoạt động của mẫu, về cơ bản chúng là sơ đồ cho trình biên dịch để biết phải xây dựng gì, vì vậy lệnh gọi đầu tiên là Test(&Callback); Tôi đã mong đợi làm việc vì trình biên dịch sẽ thấy mẫu nhận địa chỉ hàm và sẽ giả định đối số là một con trỏ.

Nhưng cuộc gọi thứ hai là gì? Mẫu giả định là gì? Một bản sao của một functio (nếu điều đó thậm chí làm cho bất kỳ ý nghĩa)?

Trả lời

14

Một hàm được chuyển đổi hoàn toàn thành con trỏ đến chính nó; chuyển đổi này xảy ra khá nhiều ở khắp mọi nơi. Test(Callback) hoàn toàn giống với Test(&Callback). Không có sự khác biệt. Trong cả hai trường hợp, Func được suy ra là void(*)(int).

Con trỏ hàm là lạ. Bạn có thể tìm hiểu thêm về chúng trong "Why do all these crazy function pointer definitions all work?"

+0

cảm ơn câu trả lời. vì vậy nếu tôi không sử dụng mẫu và tuyên bố Test như: void Test (void (* callback) (int)) {...} cả hai cuộc gọi sẽ làm việc là tốt. thats tốt để biết. bị bệnh chắc chắn rằng tôi đọc các chủ đề bạn liên kết. – sap

3

Trong C++, hàm không phải là đối tượng hạng nhất, có nghĩa là "hàm làm giá trị" không có ý nghĩa gì trong đó. Đó là lý do tại sao tên hàm luôn luôn được chuyển đổi hoàn toàn thành con trỏ đến nó.

+0

Có thể đáng chú ý hơn là có những ngôn ngữ mà “chức năng theo giá trị” có ý nghĩa. – hamstergene

2

Hàm được chuyển đổi hoàn toàn thành con trỏ hàm. Nếu thực tế không có cách nào để có được một giá trị hàm hoặc tham chiếu. Mặc dù kỳ quặc bạn có thể tạo ra một loại giá trị hàm, bạn không thể chỉ định bất cứ thứ gì cho nó.

Here is code snippit minh họa cách lambdas và các cuộc gọi lại khác nhau phản ứng với mẫu.

+0

cảm ơn mã, thực sự hữu ích. – sap

+0

Điều này là sai. Chức năng tham chiếu là tốt. Nếu 'Test' được khai báo là' void Test (Func & callback) ', thì' Func' sẽ được suy ra thành 'void (int)', và 'Callback' sẽ được chuyển qua tham chiếu, mà không được chuyển đổi thành con trỏ, thành' Kiểm tra'. –

+0

Thật tuyệt vời! Tôi đoán nó có ý nghĩa là tài liệu tham khảo nên được hỗ trợ cũng như con trỏ vì chúng rất giống nhau. Có thể khai báo một giá trị hàm và gán một cái gì đó cho nó không? –

0

Trong C++ 11 (và tăng và tr1) chúng tôi có std :: chức năng như một loại mẫu để lưu trữ functors, lambdas và chức năng. Vì vậy, bạn chắc chắn có thể có khái niệm về việc giữ một giá trị hàm trong một biến kiểu std :: function. biến đó cũng có thể là "trống" nghĩa là không có hàm (tham chiếu) nào được lưu trữ trong nó. Thế thì nó không thể được gọi.

Câu hỏi ban đầu liên quan đến điều đó trái với C, C++ cho phép tham chiếu hàm. Thêm vào đó, vì lý do tương thích với C, tên hàm có thể làm thoái hóa con trỏ hàm. Nhưng vì quá tải những thứ có nhiều "thú vị" trong C++ hơn trong C.

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