【发布时间】:2021-11-12 21:46:20
【问题描述】:
所以我正在为一个类写operator<<重载,如下所示:
#test.hh
#pragma once
#include<iostream>
namespace ns {
struct test {
double d;
test(double x): d(x) {}
friend std::ostream& operator<<(std::ostream&, const test&);
};
}
#test.cc
#include"./test.hh"
std::ostream& operator<<(std::ostream& os, const ns::test& a) {
os << a.d;
return os;
}
使用以下主要测试:
#main.cc
#include"./test.hh"
#include<iostream>
int main() {
ns::test a(12);
std::cout << a << std::endl;
return 0;
}
使用g++ test.cc main.cc 编译时返回错误:
/usr/sbin/ld: /tmp/cc6Rs93V.o: in function `main':
main.cc:(.text+0x41): undefined reference to `ns::operator<<(std::ostream&, ns::test const&)'
collect2: error: ld returned 1 exit status
显然编译器将函数解析为ns::operator<<,而它应该调用operator<<。我知道 C++ 会在参数的命名空间中找到函数,但是我是否错误地实现了运算符重载? Answers like this 似乎和我有相同的实现,唯一的区别是它们都写在标题中。
我做错了哪一部分?我该如何解决这样的问题?
【问题讨论】:
-
您是否尝试将实现放在与声明相同的命名空间中? (包裹在
namespace ns { }中) -
@JoachimIsaksson 添加命名空间包装确实解决了这个问题,但为什么呢?我的意思是如果我在
test.cc中写std::ostream& ns::operator<<,它给了我has not been decla|~ red within ‘ns’ ... note: only here as a ‘friend’。还有像这样的运算符(operator<<,operator+),不应该在全局范围内定义吗?因为我们只是用不同的参数重载它(这里ns::test作为第二个参数)。 -
@Andrew.Wolphoe 朋友声明很奇怪。它们仅对某些类型的名称查找可见,而对其他类型不可见。
-
friend std::ostream& operator<<(std::ostream&, const test&);在找到声明的命名空间中声明operator<<。如果你想声明一个全局的operator<<,你可以这样做:friend std::ostream& ::operator<<(std::ostream&, const test&);,但前提是::operator<<的声明此时已经可见。我不推荐它,因为它会污染全局命名空间。在namespace ns中声明和定义operator<<,这就是命名空间的使用方式。
标签: c++ namespaces operator-overloading header-files