Tôi muốn implemnent một nhà điều hành < < cho streaming lớp học của tôi (nói nó được đặt tên Paragraph
). Lớp Paragraph
có một số dữ liệu cá nhân, mà lý do tôi muốn (freestanding) điều hành < < chức năng để trở thành một người bạn. Vì vậy, tôi làm như được đề xuất, ví dụ: here on SO. friend
tuyên bố, triển khai operator<<
và tất cả đều tốt.Tôi có thực sự cần phải uốn cong ngược lại cho một toán tử << cho một lớp trong không gian tên không?
Nhưng bây giờ tôi muốn đặt đoạn bên trong một không gian tên, nói namespace foo
. Nó không còn hoạt động nữa! Nếu tôi viết:
namespace foo {
class Paragraph {
public:
explicit Paragraph(std::string const& init) :m_para(init) {}
std::string const& to_str() const { return m_para; }
private:
friend std::ostream & operator<<(std::ostream &os, const Paragraph& p);
std::string m_para;
};
} // namespace foo
Trình biên dịch cho tôi biết bạn đã kết bạn với foo::operator<<
, chứ không phải ::operator<<
. Được rồi. Vì vậy, tôi thay thế dòng người bạn với:
friend std::ostream & ::operator<<(std::ostream &os, const Paragraph& p);
nhưng tôi nhận được một lỗi nữa (từ GCC 5.4.0), nói với tôi ::operator<<
đã không có được công bố. Ok, hãy khai báo nó. Công việc này có hoạt động không ?:
namespace foo {
std::ostream & ::operator<<(std::ostream &os, const foo::Paragraph& p);
class Paragraph {
public:
explicit Paragraph(std::string const& init) :m_para(init) {}
std::string const& to_str() const { return m_para; }
private:
friend std::ostream & operator<<(std::ostream &os, const Paragraph& p);
std::string m_para;
};
} // namespace foo
Không, nó không biết về đoạn văn khi đọc tuyên bố ::operator<
. Ok, hãy chuyển tiếp tuyên bố:
namespace foo {
class Paragraph;
std::ostream & ::operator<<(std::ostream &os, const foo::Paragraph& p);
class Paragraph { /* actual definition here */ } }
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p) { /* impl */ }
không may mắn. Tôi gặp lỗi lạ:
f.cpp:23:16: note: candidate: std::ostream& operator<<(std::ostream&, const foo::Paragraph&)
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p)
^
f.cpp:11:15: note: candidate: std::ostream& operator<<(std::ostream&, const foo::Paragraph&)
std::ostream& ::operator<<(std::ostream &os, const foo::Paragraph& p);
... và ở đây tôi đã nghĩ không gian tên chung và không gian tên :: đều giống nhau ... không? ' (thở dài). Dù sao đi nữa, hãy chuyển tờ khai ra khỏi không gian tên:
class foo::Paragraph;
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p);
namespace foo { class Paragraph { /* actual definition here */ } }
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p) { /* impl */ }
Vẫn chưa đủ, bây giờ tôi gặp lỗi "'foo' chưa được khai báo". (Granshes răng) tốt! Theo cách đó!
namespace foo { class Paragraph; }
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p);
namespace foo { class Paragraph { /* actual definition here */ } }
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p) { /* impl */ }
vì vậy điều này, nhưng không kém phần này, hoạt động. Đó là khủng khiếp! Chắc chắn phải có một số cách tiết kiệm hơn để làm điều đó ... đúng không?
Lưu ý: Giả sử operator<<
không thể được gạch chân và phải được xác định riêng.
Câu đầu tiên của bạn chạm vào đầu móng. Hoặc có lẽ tôi nên nói đầu của tôi. – einpoklum
@einpoklum Hơn nữa, đây là giải pháp duy nhất đảm bảo tra cứu tên sẽ thành công. ':: operator <<' sẽ không được tìm thấy trong một số ngữ cảnh, vì nó không phải là một phần của bộ tra cứu ADL. –