Câu hỏi này dựa trên một tên gọi là tên được tiêm lớp. Từ [lớp]
Một class-name được đưa vào phạm vi trong đó nó được tuyên bố ngay sau khi class-name được nhìn thấy. Tên lớp cũng được chèn vào phạm vi của lớp đó; tên này được gọi là tên lớp được tiêm. Để kiểm tra quyền truy cập, tên lớp được tiêm được coi như là tên thành viên công khai.
Và từ [temp.local]:
Giống như (không mẫu) các lớp học bình thường, lớp mẫu có một tiêm-class-name (khoản 9). Bạn có thể sử dụng tên lớp được tiêm làm mẫu mẫu hoặc loại tên. Khi nó được sử dụng với một mẫu đối số-list, như một mẫu đối số cho một mẫu mẫu tham số, hoặc như nhận diện cuối cùng trong xây dựng-type-specifier của một lớp mẫu người bạn tuyên bố, nó đề cập đến bản thân mẫu lớp. Nếu không, số này tương đương với tên mẫu theo sau là mẫu tham số của mẫu lớp được đính kèm trong <>
.
Đó là, trong các định nghĩa Bar1<T>
hoặc Bar2<T>
, bạn có thể sử dụng Bar1
hoặc Bar2
để tham khảo các kiểu lớp đầy đủ. Tức là, các khai báo này tương đương:
void Foo(Bar2<T> const & other);
void Foo(Bar2 const & other);
Tuy nhiên, quy tắc tra cứu được áp dụng như bình thường. Trong khi có là tên được phân loại cho Base
, đó là tên phụ thuộc và vì vậy không thể tìm thấy thông qua tra cứu không đủ tiêu chuẩn bình thường. Từ [temp.dep]:
Trong định nghĩa của một lớp hoặc lớp mẫu, phạm vi của một lớp cơ sở phụ thuộc (14.6.2.1) không được kiểm tra trong tra cứu tên không đủ tiêu chuẩn tại thời điểm định nghĩa của lớp mẫu một hoặc thành viên hoặc trong quá trình khởi tạo mẫu lớp hoặc thành viên.
mà làm cho điều này:
Bar1() : Base() {}
vô hình thành. Base
là tra cứu không đủ tiêu chuẩn và không có tên như vậy Base
. Có một số Base<T>::Base
(tên được tiêm ở đó), nhưng phạm vi đó không được xác định. Bạn sẽ phải hoặc là làm tra cứu trình độ:
Bar1() : Bar1<T>::Base() {}
Bar1() : Bar1::Base() { }
hay không dựa vào tiêm-class-name của Base
:
Bar1() : Base<T>() { }
VS là sai trong việc chấp nhận Bar1
. Bar2
hoàn toàn OK, nếu tiết lộ chi tiết hơn là hoàn toàn có thể. Không có gì sai với điều đó.
Cần lưu ý rằng nếu còn cơ sở này không phụ thuộc, bạn vẫn có thể sử dụng tiêm-class-name của nó ngay cả khi nó là một mẫu:
template <class T> struct Base { };
struct Derived : Base<int> {
Derived() : Base() { } // OK, lookup finds Base<int>::Base
};
Nếu tôi không nhầm, chỉ có 'Bar2' là cú pháp chính xác. Bạn đã sử dụng trình biên dịch nào và bạn có thực sự gọi tất cả các hàm tạo của 'Bar1' không? – MikeMB
Biểu mẫu đầu tiên không hoạt động, vì nó trys để tham chiếu đến tên lớp được tiêm (hoạt động như một thành viên công khai) của một lớp cơ sở phụ thuộc. Bạn phải đang sử dụng MSVC, không thực hiện đúng quy tắc tra cứu tên. – cpplearner
Đó là Visual Studio 2013. Tôi đã tạo một repo đơn giản và nó biên dịch và mọi thứ được mong đợi (hoạt động chính xác). Vâng đó là cpplearner thú vị. Những thói quen xấu chúng tôi nhận được vì những thứ như thế này. – Robinson