我真的需要为朋友 operator<< 为命名空间中的 class 竭尽全力吗?
Do I really need to bend over backwards for a friend operator<< for a class in a namespace?
我想实现一个运算符<<来流式传输我的 class(比如说它的名字是 Paragraph
)。 Class Paragraph
有一些私有数据,因此我希望(独立的)operator<< 函数成为朋友。所以,我按照建议去做,例如 here on SO。 friend
语句,执行 operator<<
一切正常。
但现在我想将 Paragraph 放在命名空间中,比如 namespace foo
。它不再有效!如果我写:
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
编译器告诉我我是 foo::operator<<
,而不是 ::operator<<
。好,可以。因此,我将朋友行替换为:
friend std::ostream & ::operator<<(std::ostream &os, const Paragraph& p);
但我再次收到错误消息(来自 GCC 5.4.0),告诉我 ::operator<<
尚未声明。好的,那我们就声明一下吧。这行得通吗?:
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
不,它在阅读::operator<
的声明时不知道段落。好的,让我们转发声明:
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 */ }
运气不好。我收到奇怪的错误:
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);
... 在这里我在想全局命名空间和 :: 命名空间是同一回事...不是吗? (叹)。不管了,我们把声明移出命名空间:
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 */ }
仍然不够好,现在我收到“'foo' 尚未声明”错误。 (咬牙切齿)好!就这样吧!
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 */ }
所以这个,但不少于这个,有效。那是可怕的!肯定有某种不那么冗长的方法来做到这一点......对吗?
注:假设operator<<
不能内联,必须单独定义。
只需将 <<
运算符的定义与 Paragraph
一起放在命名空间中。当您将 Paragraph
对象插入流中时,依赖于参数的查找将找到它。
// myheader.h:
namespace ns {
struct x {
/* ... */
friend std::ostream& operator<<(std::ostream&, const x&);
};
}
// myheader.cpp:
#include "myheader.h"
namespace ns {
std::ostream& operator<<(std::ostream& os, const x& xx) {
os << xx.whatever() << '\n';
return os;
}
}
或者,如果它小到需要内联,就这样做:
// myheader.h:
namespace ns {
struct x {
/* ... */
friend std::ostream& operator<<(std::ostream&, const x&);
};
inline std::ostream& operator<<(std::ostream& os, const x& xx) {
os << xx.whatever() << '\n';
return os;
}
}
您的问题似乎源于没有意识到 ADL 如何找到正确的 operator<<
,只要它与 Paragraph
的名称空间相同。扩展你的第一个例子
// this is what you have already
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
// Now we can add a definition here, or in a different TU
namespace foo {
std::ostream& operator<<(std::ostream& os, const Paragraph& p) {
return os << p.m_para;
}
} // namespace foo
int main() {
foo::Paragraph p("hello");
// finds your operator<< using adl
std::cout << p << '\n';
}
我想实现一个运算符<<来流式传输我的 class(比如说它的名字是 Paragraph
)。 Class Paragraph
有一些私有数据,因此我希望(独立的)operator<< 函数成为朋友。所以,我按照建议去做,例如 here on SO。 friend
语句,执行 operator<<
一切正常。
但现在我想将 Paragraph 放在命名空间中,比如 namespace foo
。它不再有效!如果我写:
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
编译器告诉我我是 foo::operator<<
,而不是 ::operator<<
。好,可以。因此,我将朋友行替换为:
friend std::ostream & ::operator<<(std::ostream &os, const Paragraph& p);
但我再次收到错误消息(来自 GCC 5.4.0),告诉我 ::operator<<
尚未声明。好的,那我们就声明一下吧。这行得通吗?:
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
不,它在阅读::operator<
的声明时不知道段落。好的,让我们转发声明:
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 */ }
运气不好。我收到奇怪的错误:
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);
... 在这里我在想全局命名空间和 :: 命名空间是同一回事...不是吗? (叹)。不管了,我们把声明移出命名空间:
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 */ }
仍然不够好,现在我收到“'foo' 尚未声明”错误。 (咬牙切齿)好!就这样吧!
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 */ }
所以这个,但不少于这个,有效。那是可怕的!肯定有某种不那么冗长的方法来做到这一点......对吗?
注:假设operator<<
不能内联,必须单独定义。
只需将 <<
运算符的定义与 Paragraph
一起放在命名空间中。当您将 Paragraph
对象插入流中时,依赖于参数的查找将找到它。
// myheader.h:
namespace ns {
struct x {
/* ... */
friend std::ostream& operator<<(std::ostream&, const x&);
};
}
// myheader.cpp:
#include "myheader.h"
namespace ns {
std::ostream& operator<<(std::ostream& os, const x& xx) {
os << xx.whatever() << '\n';
return os;
}
}
或者,如果它小到需要内联,就这样做:
// myheader.h:
namespace ns {
struct x {
/* ... */
friend std::ostream& operator<<(std::ostream&, const x&);
};
inline std::ostream& operator<<(std::ostream& os, const x& xx) {
os << xx.whatever() << '\n';
return os;
}
}
您的问题似乎源于没有意识到 ADL 如何找到正确的 operator<<
,只要它与 Paragraph
的名称空间相同。扩展你的第一个例子
// this is what you have already
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
// Now we can add a definition here, or in a different TU
namespace foo {
std::ostream& operator<<(std::ostream& os, const Paragraph& p) {
return os << p.m_para;
}
} // namespace foo
int main() {
foo::Paragraph p("hello");
// finds your operator<< using adl
std::cout << p << '\n';
}