2012-09-24 23 views
5

Với đoạn mã sau:Moving Template Method để Breaks phái sinh Compilation

template<typename T> 
class A 
{ 
public: 
    T t; 
}; 

class B 
{ 
public: 
    void foo(int i) {} 

    template<typename T> 
    void foo(A<T>& a) {} 
}; 

int main() 
{ 
    A<int> a; 
    B  b; 

    b.foo(a ); 
    b.foo(a.t); 
} 

này biên dịch và hoạt động tốt; các phiên bản quá tải chính xác của B::foo() được chọn và được gọi là aa.t.

Bây giờ tôi giới thiệu một lớp mới C mà xuất phát từ B và di chuyển các phiên bản mẫu của ::foo() ra khỏi B và thành C:

template<typename T> 
class A 
{ 
public: 
    T t; 
}; 

class B 
{ 
public: 
    void foo(int i) {} 
}; 

class C: public B 
{ 
public: 
    template<typename T> 
    void foo(A<T>& a) {} 
}; 

int main() 
{ 
    A<int> a; 
    C  c; 

    c.foo(a ); // Fine 
    c.foo(a.t); // Error 
} 

Và bây giờ mã sẽ không biên dịch nữa. Visual Studio 2005 được nêu:

error C2784: 'void C::foo(A<T> &)' : could not deduce template argument for 'A<T> &' from 'int' 

Trong thực tế, gọi C::foo() với bất kỳ int kết quả giá trị do lỗi này. Nó gần như có vẻ như quá tải phương thức cho int đang bị ẩn bởi quá tải mẫu.

Tại sao điều này lại xảy ra? Có một số vấn đề với trình biên dịch Visual Studio 2005? Thật không may, tôi không thể kiểm tra nó trên bất kỳ trình biên dịch khác ngay bây giờ.

Mọi thông tin đều được đánh giá cao.

Trả lời

5

Nó gần như có vẻ như quá tải phương pháp để int đang được ẩn bởi mẫu quá tải.

Chính xác! Bạn cần thêm tuyên bố sử dụng vào lớp C:

class C: public B 
{ 
public: 
    using B::foo; 
    template<typename T> 
    void foo(A<T>& a) {} 
}; 

Khi bạn khai báo hàm thành viên trong lớp dẫn xuất, tất cả các hàm thành viên trong lớp cơ sở có cùng tên sẽ bị ẩn. Xem §3.3.10/3 của ISO/IEC 14882: 2011:

Tuyên bố thành viên trong lớp dẫn xuất (khoản 10) ẩn khai báo thành viên của một lớp cơ sở cùng tên; xem 10.2.

2

Ẩn, không bị quá tải. Sử dụng

class C: public B 
{ 
public: 
    using B::foo; 
    template<typename T> 
    void foo(A<T>& a) {} 
}; 
1

Đúng, hàm cơ sở là ẩn. Đó thực sự là thuật ngữ thích hợp cho nó. Thêm using B::foo; vào định nghĩa lớp học C để hiện nó.