2012-06-12 34 views
12

Có mã này:Chuyển tiếp tuyên bố của lớp được sử dụng trong mẫu chức năng không được biên dịch bởi kêu vang ++

class A; 

template <class T> 
void fun() { 
    A a; 
} 

class A { 
public: 
    A() { } 
}; 

int main() { 
    fun<int>(); 
    return 0; 
} 

g ++ 4.5 và g ++ 4.7 biên dịch này mà không có lỗi. Nhưng clang ++ 3.2 (thân cây) đưa ra lỗi này:

main.cpp:5:6: error: variable has incomplete type 'A' 
    A a; 
    ^
main.cpp:1:7: note: forward declaration of 'A' 
class A; 
    ^

Trình biên dịch nào đúng theo tiêu chuẩn C++?

+1

Vì bạn cố gắng tạo một đối tượng kiểu 'A' trình biên dịch phải biết kích thước của nó mà nó không thể biết mà không nhìn thấy định nghĩa đầy đủ, vì vậy clang sẽ ở ngay đây (nhưng tôi không có tham chiếu std) . –

+0

Có bất kỳ công tắc nào do clang cung cấp để biên dịch mã như vậy không? – Sashank

Trả lời

12

Which compiler is right then according to C++ standard?

Cả hai đều chính xác. Đây là một chương trình hình thành bệnh tật. Mỏ nhấn mạnh:

N3290 14.6¶9
If a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is done, and if the completeness of that type affects whether or not the program is well-formed or affects the semantics of the program, the program is ill-formed; no diagnostic is required.

Clang ++ và các trình biên dịch khác đưa ra chẩn đoán ở đây là tính năng bổ sung đáng yêu, nhưng chẩn đoán không bắt buộc. Điều khoản đó "chương trình là hình thành không đúng, không cần chẩn đoán" cung cấp cho một nhà phát triển trình biên dịch miễn phí để làm bất cứ điều gì trong hoàn cảnh như vậy và vẫn tuân thủ.

+0

tại sao lập trình viên sau đó thậm chí không được thông báo bởi g ++ rằng có điều gì đó sai? nó sẽ được như vậy mà cả hai trình biên dịch là chính xác nhưng một trong những hiện công việc của mình và thứ hai làm một cái gì đó rất khác nhau? – scdmb

+1

Mục đích là để cho phép xử lý mẫu lười biếng. Tiêu chuẩn này cho phép các triển khai trì hoãn việc phân tích cú pháp chi tiết đến điểm mà tại đó một khuôn mẫu được khởi tạo. Lớp 'A' được biết ở điểm khởi tạo, do đó nó biên dịch.Nó vẫn chưa được định dạng vì một tệp khác có thể '# include' định nghĩa mẫu của bạn, xác định một lớp hoàn toàn khác' A' và tạo một 'fun ()' khác nhau. Điều này sẽ không liên kết vì nó vi phạm quy tắc một định nghĩa (ngay cả khi bạn đủ điều kiện 'vui vẻ' là' nội tuyến'). –

5

Clang là chính xác, theo như tôi biết. Tại chức năng của bạn vui vẻ, bạn không biết kích thước của A, và kể từ khi phân bổ một A, bạn cần phải biết kích thước của nó. Theo tôi, gcc là cách để tha thứ ở đây.

+0

clang là tốt đẹp bằng cách phát hiện vấn đề, nhưng gcc của thiếu chẩn đoán cũng là chính xác. Xem câu trả lời của tôi để biết chi tiết. –

0

biên dịch Comeau của không thích nó, hoặc:

"ComeauTest.c", line 5: error: incomplete type is not allowed 
    A a; 
    ^

Tuy nhiên những nỗ lực của tôi trong việc tìm chương và thơ trong chuẩn C++ là không kết quả. Nó dường như ẩn giữa các dòng và tương tác của "điểm của instantiation", "tên độ phân giải". Các đoạn 14.6/8 và 14.6/9 của tiêu chuẩn năm 2003 có vẻ phù hợp.

+0

tôi không có spec trong tay, nhưng tôi biết rằng một quy tắc đã được thêm vào (như là một độ phân giải DR) để render mã của mình "illformed; không cần chẩn đoán" đôi khi sau khi C++ 98 hoặc C++ 03. nó nằm trong đoạn nói về các định nghĩa mẫu không đúng định dạng. –

1

clang++ đang sử dụng các hành vi đúng, điều này được mô tả trong phần 4.6/9 của tiêu chuẩn (n1905).


Templates 14.6/9 Name resolution

If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template definition; the name is bound to the declaration (or declarations) found at that point and this binding is not affected by declarations that are visible at the point of instantiation.


Để đặt mọi thứ trong điều kiện đơn giản; nếu tên là không phải phụ thuộc vào thông số mẫu, nó phải nằm trong phạm vi mà định nghĩa được tìm thấy; do đó bạn cần phải xác định A trước định nghĩa của mình là template<typename T> void fun().

+2

N1905 hơi cũ. Đó là từ năm 2005. N3291 là (tôi nghĩ) bản thảo cuối cùng. –

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