2010-10-21 24 views
8

Điều gì sai với mã của tôi?C++ mẫu người bạn điều hành quá tải

template<int E, int F> 
class Float 
{ 
friend Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs); 
}; 

G ++ chỉ giữ cảnh báo:

float.h:7: warning: friend declaration ‘Float<E, F> operator+(const Float<E, F>&, const Float<E, F>&)’ declares a non-template function

float.h:7: warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning

Tôi cố gắng để add <> after the function name here như đã đề cập trong các lưu ý cảnh báo, nhưng g ++ mang lại cho tôi một lỗi.

Tôi đã biên dịch mã bằng clang ++, không sao, không có cảnh báo nào cả.

+3

Bạn có thể muốn đọc http://www.parashift.com/c++-faq-lite/templates.html#faq-35.16 – UncleBens

Trả lời

24

Đó chỉ là một cảnh báo về khía cạnh phức tạp của ngôn ngữ. Khi bạn khai báo một hàm friend, nó không phải là thành viên của lớp khai báo. Bạn có thể định nghĩa nó ở đó để thuận tiện, nhưng nó thực sự thuộc về không gian tên.

Khai báo hàm bạn bè không phải là mẫu, bên trong mẫu lớp, vẫn khai báo hàm không phải mẫu trong không gian tên. Nó không phải là một thành viên của lớp, cũng không phải là một khuôn mẫu. Tuy nhiên, đó là đã tạo ra theo mẫu lớp học.

Tạo các chức năng không phải mẫu từ một mẫu có chút mơ hồ. Ví dụ: bạn không thể thêm tuyên bố cho hàm đó bên ngoài khối class. Vì vậy, bạn phải định nghĩa nó bên trong khối class, điều này có ý nghĩa bởi vì mẫu lớp sẽ tạo ra nó.

Một điều khó khăn khác về bạn bè là việc khai báo bên trong class Float {} không khai báo hàm trong không gian tên. Bạn chỉ có thể tìm thấy nó thông qua độ phân giải quá tải phụ thuộc vào ý nghĩa của đối số, tức là chỉ định một đối số có loại Float (hoặc một tham chiếu hoặc con trỏ). Đây không phải là một vấn đề cho operator+, vì nó có khả năng bị quá tải dù sao, và nó sẽ không bao giờ được gọi ngoại trừ với các loại do người dùng định nghĩa.

Ví dụ về một vấn đề tiềm ẩn, hãy tưởng tượng bạn có một hàm tạo chuyển đổi Float::Float(Bignum const&). Nhưng Bignum không có operator+. (Xin lỗi, ví dụ giả tạo.) Bạn muốn dựa vào operator+(Float const&, Float const&) để thêm Bignum. Bây giờ my_bignum + 3 sẽ không biên dịch vì toán hạng không phải là Float để nó không thể tìm thấy hàm friend.

Có thể, bạn không có gì phải lo lắng, miễn là hàm được đề cập là operator.

Hoặc bạn cũng có thể thay đổi friend làm mẫu. Trong trường hợp đó, nó phải được xác định bên ngoài khối class {} và được khai báo trước đó, thay vì cần được khai báo và xác định bên trong.

template<int E, int F> // now this is a template! 
Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs); 

template<int E, int F> 
class Float 
{ 
    // deduce arguments E and F - this names operator+< E, F >. 
friend Float<E, F> operator+<> (const Float<E, F> &lhs, const Float<E, F> &rhs); 
}; 
+1

Cảm ơn bạn đã trả lời tốt. –

1

Bạn cần phải làm đúng như những lời cảnh báo nói:

template<int E, int F> 
Float<E, F> operator+ (const Float<E, F> &lhs, const Float<E, F> &rhs); 

template<int E, int F> 
class Float 
{ 
friend Float<E, F> operator+<> (const Float<E, F> &lhs, const Float<E, F> &rhs); 
}; 

này tuyên bố một chuyên môn đầy đủ của mẫu điều hành một người bạn của một trường hợp cụ thể của lớp mẫu. Trong một bình luận cho câu hỏi, Bác sĩ đã vui lòng cung cấp a link to an explanation lý do tại sao điều đó phức tạp đến vậy.

+0

@Potatoswatter: Tuyên bố bạn khai tuyên bố chuyên môn cụ thể là bạn của lớp, Không? – sbi

+0

Thực ra, tôi chỉ thử nghiệm mã của sbi và nó hoạt động với g ++ của tôi. –

+0

@Zifei: Đoạn mã này hoạt động nhưng yêu cầu phải thay đổi định nghĩa của hàm. (Xin lỗi, tôi không nhận thấy sự thay đổi đối với biểu mẫu của hàm.) – Potatoswatter

3

Đây là chủ đề cũ nhưng tôi nghĩ cách dễ nhất để khai báo toán tử là định nghĩa nó trong lớp Float.

template<int E, int F> 
class Float 
{ 
public: 
    friend Float operator+ (const Float &lhs, const Float &rhs) 
    { 
     // Whatever you need to do. 
    } 
}; 

Cú pháp dễ viết và dễ hiểu hơn và nó sẽ hoạt động giống hệt nhau (ngoại trừ nó sẽ được gạch chân), nó sẽ không phải là chức năng thành viên.

MSDN: Chức năng bạn bè được xác định trong khai báo lớp không được xem xét trong phạm vi của lớp kèm theo; chúng nằm trong phạm vi tệp.

+0

Không, trong trường hợp của 'toán tử +', nói chung cách dễ nhất và tốt nhất là thực hiện 'toán tử + =' làm thành viên, và sau đó thực hiện 'toán tử +' với tư cách là một người không phải thành viên trong điều khoản của '+ = '. Điều này đảm bảo bạn có cả hai toán tử được xác định và chúng hoạt động nhất quán. –

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