我发现 C++ 解析运算符重载的奇怪行为,我无法解释自己。指向一些描述它的资源的指针与答案一样好。
我有 2 个翻译单元。在一个(称为 util.cpp/h)中,我声明并定义了两个运算符(为了可读性,我省略了真正的实现,无论如何都会出现问题):
// util.h
#ifndef GUARD_UTIL
#define GUARD_UTIL
#include <iostream>
std::istream& operator>>(std::istream& is, const char* str);
std::istream& operator>>(std::istream& is, char* str);
#endif
和:
//util.cpp
#include "util.h"
#include <iostream>
std::istream& operator>>(std::istream& is, const char* str) {
return is;
}
std::istream& operator>>(std::istream& is, char* str) {
return is;
}
这些运算符当然是在全局命名空间中,因为它们对标准类型和内置类型进行操作,并且应该可以在任何地方使用。它们可以从全局命名空间(例如从 main())或显式告诉编译器它们在全局命名空间中正常工作(参见代码示例)。
在另一个翻译单元(称为 test.cpp/h)中,我在命名空间中使用这些运算符。这一直有效,直到我将类似的运算符放入此命名空间。一旦添加了此运算符,编译器(例如 gcc 或 clang)就无法再找到可行的运算符>>。
// test.h
#ifndef GUARD_TEST
#define GUARD_TEST
#include <iostream>
namespace Namespace {
class SomeClass {
public:
void test(std::istream& is);
};
// without the following line everything compiles just fine
std::istream& operator>>(std::istream& is, SomeClass& obj) { return is; };
}
#endif
和:
//test.cpp
#include "test.h"
#include "util.h"
#include <iostream>
void Namespace::SomeClass::test(std::istream& is) {
::operator>>(is, "c"); //works
is >> "c" //fails
}
为什么在命名空间中没有运算符>>时编译器会找到正确的运算符,但当有一个时却找不到?为什么即使它具有不同的签名,运算符也会影响编译器找到正确的能力?
解决此问题的一种尝试是
std::istream& operator>>(std::istream& is, const char* str) { ::operator>>(is, str); }
进入命名空间,但链接器抱怨以前的定义。所以附加:为什么链接器可以找到编译器找不到的东西?