2012-12-17 35 views
7

Trong ví dụ sau, Foo không thực hiện những gì được dự định, nhưng tôi không thể hiểu tại sao điều này được phép biên dịch.Sử dụng tham chiếu làm loại mẫu

#include <string> 
#include <iostream> 

typedef std::string& T; 

T Foo(int & i) 
{ 
    return T(i); 
} 

int main() 
{ 
    int a = 1; 
    std::string & s = Foo(a); 
} 

Tôi phát hiện ra điều này với các mẫu, nhưng typedef cho thấy rằng nó không liên quan đến mẫu. Không cần phải nói, s không phải là chuỗi hợp lệ tại đây. Tôi nghĩ rằng việc xây dựng giá trị trong sự trở lại của Foo sẽ tạo ra một lỗi biên dịch.

Tôi thiếu gì ở đây?

+0

Không gây sốc kinh khủng cho chuyên môn của bạn không được gọi nếu bạn đang gọi 'Foo (a);' và mong muốn chuyên môn hóa 'Foo () 'sẽ được kích hoạt. – WhozCraig

+0

@WhozCraig Tôi đồng ý, tôi đã tuyệt vọng vì nó không có ý nghĩa. – JaredC

+0

Nó, tất nhiên, cháy, nếu bạn trực tiếp gọi 'Foo () ', nhưng đó không thực sự là những gì bạn đang tìm kiếm, không có nghi ngờ. – WhozCraig

Trả lời

6

Trước hết, nó có giá trị gì rằng vấn đề thực sự không có mối quan hệ với các mẫu vì mã này biên dịch một cái giếng:

typedef std::string& T; 
T Foo(int& i) { 
    return T(i); 
} 

Lý do tôi nghĩ này biên dịch là báo cáo kết quả return tương đương với

return reinterpret_cast<T>(i); 

trong trường hợp T là một thành viên tham chiếu. ... và điều này, tất nhiên, biên dịch: Bạn đã hứa bạn biết những gì bạn đang làm và yêu cầu trình biên dịch vui lòng tin bạn.

OK, tìm thấy nó ở 5.2.3 [expr.type.conv] đoạn 1:

... Nếu danh sách biểu thức là một biểu thức duy nhất, khái niệm loại chuyển đổi tương đương (trong definedness, và nếu được định nghĩa theo nghĩa) với biểu thức truyền tương ứng (5.4). ...

... và 5,4 [expr.cast] Đoạn 4:

Quá trình chuyển đổi được thực hiện bởi [các hình thức khác của dàn diễn viên] một reinterpret_cast (5.2.10) [...] có thể được thực hiện bằng cách sử dụng ký pháp đúc của chuyển đổi loại rõ ràng. [...]

(các elisions bao gồm các trường hợp liên quan đến người sử dụng định nghĩa loại, tích hợp chuyển đổi loại hình, const chuyển đổi, vv)

+0

Bạn có thể mở rộng trên * tại sao * 'reinterpret_cast' được gọi trong trường hợp này khi T là tham chiếu không? – JaredC

+0

Chà, điều đó thật tinh tế, đặc biệt là khi sử dụng các mẫu. Tôi thấy một câu hỏi tiếp theo về việc cấm loại tham chiếu cho 'T' trong trường hợp này ... – JaredC

+0

xem phần cuối câu trả lời của tôi về cách cấm nó –

5

này không có gì để làm với các mẫu, bạn sẽ có được kết quả tương tự nếu T chỉ là một typedef cho std::string& chứ không phải là một mẫu tham số suy luận:

#include <string> 

typedef std::string& T; 

T Foo(int & i) 
{ 
    return T(i); 
} 

int main() 
{ 
    int a = 1; 
    std::string & s = Foo(a); 
} 

câu trả lời Dietmar đã làm tôi nhận ra điều này có thể được tiếp tục đơn giản hóa để:

#include <string> 

typedef std::string& T; 

int main() 
{ 
    int a = 1; 
    std::string & s = T(a); 
} 

nơi T(a) cũng giống như các diễn viên (T)a tức (std::string&)a mà (theo các quy tắc của 5.4 [expr.cast]) sẽ làm một const_cast nếu đó là hợp lệ (mà nó không phải là) hoặc một static_cast nếu đó là hợp lệ (không phải là) hoặc static_cast nếu có giá trị là const_cast nếu đó là hợp lệ (không phải là) hoặc reinterpret_cast nếu hợp lệ () hoặc reinterpret_cast nếu số đó hợp lệ, nếu không thì biểu hiện không đúng định dạng.

Vì vậy, khi Dietmar nói, nó giống như làm một reinterpret_cast, tức là

std::string & s = reinterpret_cast<std::string&>(a); 

tôi thấy nó khá ngạc nhiên rằng mã gốc biên dịch, nhưng vì nó cũng giống như dòng trên, nó cho phép để biên dịch . Sử dụng kết quả của diễn viên là hành vi không xác định mặc dù.

Để tránh sự ngạc nhiên khi T(a) tương đương với dàn diễn viên, hãy sử dụng cú pháp khởi tạo đồng nhất C++ 11 mới, T{a}, luôn là khởi tạo chứ không phải biểu thức truyền.

Câu hỏi hay, điều tra và trả lời nó cho tôi thấy một hình ảnh xác thực mới mà trước đây tôi chưa từng biết, nhờ JaredC và Dietmar cho phần kiến ​​thức mới!

+0

Có thích hợp để chỉnh sửa câu hỏi từ xa các mẫu (kể từ khi 2 người đã nhận xét rằng cho đến nay)? Hay tôi chỉ nên rời khỏi? – JaredC

+0

Tôi nghĩ rằng đó là OK để chỉnh sửa nó ... câu hỏi là thú vị vì vậy nó làm cho tinh thần để làm rõ nó để loại bỏ các cá trích đỏ về mẫu. –

+0

@ JaredC: Tôi đồng ý với Jonathan. Tất nhiên, nó cũng có nghĩa là các câu trả lời đang được chỉnh sửa để đưa câu hỏi đã thay đổi vào tài khoản;) –

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