2013-10-03 19 views
18

Hãy nói rằng tôi có chức năng này:Hành vi của hàm C++ template

bool f(int&& one, int&& two) { } 

Nếu tôi cố gắng gọi nó với mã này:

int x = 4; 
f(x, 5); 

trình biên dịch sẽ phàn nàn rằng nó không thể chuyển đổi x từ vế trái tham chiếu đến tham chiếu rvalue, đó là chính xác.

Bây giờ nếu tôi chuyển đổi f thành một mẫu hàm như thế này:

template <class T, class U> 
bool f(T&& one, U&& two) { } 

sau đó tôi có thể gọi nó với một tài liệu tham khảo giá trị trái:

int x = 5; 
f(x, 5); 

Tại sao nó như vậy? Tại sao trình biên dịch không phàn nàn trong trường hợp này?

Trả lời

8

Bởi vì có một trích lập luận mẫu, tài liệu tham khảo sụp đổ sẽ xảy ra. Đó là những gì Scott Meyers gọi tài liệu tham khảo phổ dụng. U&& thực sự sẽ trở thành int &. Có một số article and video đẹp về cách hoạt động và cách sử dụng nó.

6

Điều này xảy ra vì tài liệu tham khảo quy tắc sụp đổ thêm vào trong C++ 11

A& & becomes A& 
A& && becomes A& 
A&& & becomes A& 
A&& && becomes A&& 

Trong mẫu các quy tắc được áp dụng nhưng không phải trong một chức năng bình thường không có tài liệu tham khảo sụp đổ bình thường trong chức năng. Có một số trường hợp cụ thể khác mà việc thu hẹp tham chiếu sẽ xảy ra như khi có sự hiện diện của auto, decltype hoặc typedef (bao gồm khai báo using) Điều đó giải thích kết quả của quá trình biên soạn. Việc thu thập tham chiếu phải được thêm vào trong C++ 11 vì nếu không, việc sử dụng các tham chiếu như A & & sẽ trở thành lỗi vì bạn không thể tham chiếu đến tham chiếu.

+2

Trong khi tham chiếu sụp đổ không xảy ra trong trường hợp của một "tham chiếu phổ quát" ma thuật thực sự xảy ra trước bước này và xảy ra trong quá trình khấu trừ đối số mẫu. Lưu ý của bạn về tham chiếu sụp đổ không hoạt động trong một chức năng bình thường chỉ đơn giản là sai; sự sụp đổ tham chiếu có thể xảy ra ở bất cứ đâu: 'sử dụng T = int &&; void foo (T & x); 'ở đây x là một' int & 'do tham chiếu sụp đổ. – Simple

+0

@Simple trông giống như quyền của bạn, tôi đã biết rằng decltypes và tự động có thể có tham chiếu sụp đổ, không biết rằng một typedef có thể gây ra nó, tôi sẽ sửa đổi câu trả lời của tôi – aaronman

10

Mỗi § 8.3.3/6. Đó là quy tắc thu gọn tham chiếu.

template <class T> void func(T&&) // Accepts rvalue or lvalue 
void func(T&&)      // Accepts rvalue only 
void func(T&)      // Accepts lvalue only 

Worth ví dụ từ dự thảo tiêu chuẩn:

int i; 
typedef int& LRI; 
typedef int&& RRI; 

LRI& r1 = i;   // r1 has the type int& 
const LRI& r2 = i;  // r2 has the type int& 
const LRI&& r3 = i; // r3 has the type int& 

RRI& r4 = i;   // r4 has the type int& 
RRI&& r5 = 5;   // r5 has the type int&& 

decltype(r2)& r6 = i; // r6 has the type int& 
decltype(r2)&& r7 = i; // r7 has the type int& 
+3

Đây là loại phản trực quan ... –

+0

@VioletGiraffe chào mừng bạn đến với thế giới của C++ –

+0

@jk .: Và tôi nghĩ tôi hiểu hầu hết thế giới này! –