2013-02-07 31 views
6

Mã dưới đây biên dịch (gcc 4.7.2 hoặc icc 13) và tạo ra "1 2" đầu ra. Điều đó có nghĩa là giảm vòng loại const, i. e., f<int&> có loại thông số int&.C++ 98/03 tham chiếu collapsing và cv vòng loại

Tại sao điều đó xảy ra? Theo tôi được biết, theo §14.3.1.4:

Nếu một mẫu đối số cho một mẫu tham số T tên một loại “tài liệu tham khảo để CV1S”, một nỗ lực để tạo ra các loại “tài liệu tham khảo để CV2T”tạo kiểu‘tham chiếu đến cv12S’, nơi cv12 là sự kết hợp của ERS fi cv-quali CV1CV2. Các cv-quali dư ​​thừa được bỏ qua.

const không được bỏ. Đây là mã:

#include <iostream> 
using namespace std; 

template <typename T> 
void f(const T& t) 
{ 
    t++; 
} 

int main() 
{ 
    int a = 1; 

    cout << a; 
    f<int&>(a); 
    cout << ' ' << a << endl; 

    return 0; 
} 
+4

Tôi không thể tìm thấy trích dẫn đó bằng C++ 98 hoặc C++ 03. §14.3.1 là "đối số kiểu mẫu" và không có tiểu mục hoặc đoạn 4. –

Trả lời

4

GCC 4.7.2 không không biên dịch này khi lá cờ -std=c++98 được chỉ định. Trong thực tế, trong C++ 98 (cũng như trong C++ 03) tham chiếu đến tham chiếu không sụp đổ.

Một cố gắng để nhanh chóng f<int&>, nơi T = int&, tạo ra chức năng chữ ký sau đây (ở đây tôi cố tình chuyển đổi vị trí của các loại lập luận Tconst specifier, được cho phép bởi vì const T& cũng giống như T const&):

void f(int& const& t) // ERROR: reference to reference is illegal 

Ở trên không hợp pháp trong C++ 98, cũng như trong C++ 03. Liên tục, đây là lỗi mà bạn nhận được từ GCC 4.7.2:

Compilation finished with errors: 
source.cpp: In function 'int main()': 
source.cpp:15:14: error: no matching function for call to 'f(int&)' 
source.cpp:15:14: note: candidate is: 
source.cpp:5:6: note: template<class T> void f(const T&) 
source.cpp:5:6: note: template argument deduction/substitution failed: 
source.cpp: In substitution of 'template<class T> void f(const T&) [with T = int&]': 
source.cpp:15:14: required from here 
source.cpp:5:6: error: forming reference to reference type 'int&' 

Tuy nhiên, nếu bạn sử dụng -std=c++11 cờ, sau đó trình biên dịch thực hiện tham khảo sụp đổ khi instantiating mẫu: một tài liệu tham khảo giá trị trái với một tài liệu tham khảo giá trị trái trở thành một tham khảo giá trị trái:

void f(int& const& t) == void f(int& t) 

Ở đây const vòng loại được giảm xuống, vì nó áp dụng cho các tài liệu tham khảo, và không để các đối tượng được tham chiếu. Vì tham chiếu không thể được gán lại, chúng tự nhiên là const, đó là lý do tại sao số const được coi là thừa và bị loại bỏ. Xem this Q&A on SO để được giải thích.

Điều đó mang lại tham chiếu giá trị lvalue cho tham chiếu giá trị lvalue, giải quyết thành tham chiếu lvalue đơn giản. Do đó, chữ ký ở bên phải được khởi tạo.

Ở trên là một ứng cử viên khả thi để giải quyết cuộc gọi cho f<int&>(a) và do đó, nó biên dịch mà không có lỗi.

+0

Làm thế nào có thể 'void f (const int & t) {t ++; } 'biên dịch? Nó sửa đổi 't' là tham chiếu const. – Kleist

+0

@Kleist: Hm, bạn nói đúng. Để tôi điều tra –

+0

Thay vì giả sử C++ 11 theo mặc định, đoạn mã trên đã hoạt động một thời gian trong gcc dưới dạng phần mở rộng (nó biên dịch ở chế độ mặc định trong 4.1, nhưng không thành công nếu bạn yêu cầu '-ansi'. –

4

Đây là năm 1770 mà trích dẫn trong câu hỏi dường như có nguồn gốc:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1770.html

14.3.1 - Mẫu kiểu lập luận

-4- Nếu một mẫu đối số cho một template- tham số T đặt một kiểu "tham chiếu lvalue tới cv1 S", một nỗ lực tạo kiểu tham chiếu "(lvalue hoặc rvalue) tới cv2 T" tạo kiểu "tham chiếu lvalue tới cv12 S", trong đó cv12 là liên kết của cv-vòng loại cv1 và cv2. Nếu đối số mẫu đặt tên kiểu "tham chiếu rvalue tới cv1 S", một nỗ lực để tạo kiểu "tham chiếu lvalue tới cv2 T" tạo kiểu "tham chiếu lvalue tới cv12 S." Nếu đối số mẫu đặt tên kiểu "tham chiếu rvalue tới cv1 S", một nỗ lực để tạo kiểu "tham chiếu rvalue tới cv2 T" tạo kiểu "tham chiếu rvalue tới cv12 S." Giá trị cv dự phòng bị bỏ qua.

Dưới đây là năm 2118 mà trích dẫn đã bị đánh ra:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html

14.3.1 - đối số kiểu mẫu

-4- Nếu một mẫu đối số cho một mẫu -tham số T đặt một loại "tham chiếu đến cv1 S" là tham chiếu đến loại A, một nỗ lực để tạo loại "tham chiếu đến cv2 T" "lvalue-reference to cv T" tạo kiểu "tham chiếu đến cv12 S", trong đó cv12 là liên kết của cv-qualifiers cv1 và cv2. Dư thừa cv-vòng loại sẽ được bỏ qua "giá trị trái tham chiếu đến A", trong khi một nỗ lực để tạo ra các loại "rvalue-tham chiếu đến cv T" tạo ra T. loại

Những gì bạn đang trích dẫn có vẻ là lỗi thời từ ngữ .

+0

Tìm thấy tốt! .... –

+0

Lưu ý: Trong phiên bản cuối cùng của C + +11, điều này đã kết thúc trong 8.3.2/5 (tức là một phần của phần dcl.ref, không còn là temp.arg.type). – jogojapan

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