2015-07-02 21 views
6

Mặc dù cả hai biên dịch sau (với Visual Studio 2013), là một trong số chúng "đúng" hơn đối với thành ngữ C++? Tôi nói đặc biệt đối với các tham số mẫu rõ ràng khi gọi các hàm tạo lớp cơ sở và khai báo các thành viên. Liệu The Standard có một cái nhìn về điều này? Có một lý do thực tế tốt để thích cái này hơn cái kia không?Thành ngữ C++ khi khai báo thành viên lớp mẫu và nhà xây dựng

template<class T> 
class Bar1 : public Base<T> 
{ 
public: 

    Bar1() : Base() {} 
    Bar1(T value) : Base(value) {} 
    Bar1(Bar1 const & other) : Base(other.value) {} 

    void Foo(Bar1 const & other) 
    { 
     // Some foo related activity. 
    } 
}; 

template<class T> 
class Bar2 : public Base<T> 
{ 
public: 

    Bar2() : Base<T>() {} 
    Bar2(T value) : Base<T>(value) {} 
    Bar2(Bar2<T> const & other) : Base<T>(other.value) {} 

    void Foo(Bar2<T> const & other) 
    { 
     // Some foo related activity. 
    } 
}; 
+1

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

+1

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

+0

Đó 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

Trả lời

2

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ó 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 
}; 
0

Biểu mẫu đầu tiên không đúng và không được biên dịch. Để xem lý do, hãy xem xét điều gì sẽ xảy ra nếu bạn nhân kế thừa từ Base<Foo>Base<Bar> (hoặc Base<T>Base<Base<T>> hoặc bất kỳ thứ gì). Làm thế nào nó có thể giải quyết sự mơ hồ? Ý tưởng rằng biểu mẫu đầu tiên sẽ hoạt động có thể xuất phát từ việc áp dụng sai quy tắc, trong định nghĩa mẫu lớp, bạn không cần phải cung cấp (các) tham số mẫu khi đề cập đến tên lớp. Điều này không áp dụng cho một lớp cơ sở templated, mặc dù.

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