【发布时间】:2013-04-12 15:51:25
【问题描述】:
通过这个示例程序,我观察到 g++ 和 clang 中的不同行为
Foo.h:
#include <iostream>
namespace Bar
{
class Foo
{
public:
Foo(int x) : _x(x)
{}
int x() const
{
return _x;
}
private:
int _x;
};
}
std::ostream& operator <<(std::ostream& os, const Bar::Foo* foo);
Foo.cpp
#include <Foo.h>
using namespace std;
ostream& operator <<(ostream& os, const Bar::Foo* foo)
{
return os << foo->x();
}
main.cpp
#include <iostream>
using namespace std;
template<typename T>
void print(const T& t)
{
cout << t << endl;
}
#include <Foo.h>
int main(int argc, char** argv)
{
Bar::Foo* foo = new Bar::Foo(5);
print(foo);
}
用clang++和g++编译会产生不同的结果:
air:~ jose$ clang++ Foo.cpp main.cpp -I.
air:~ jose$ ./a.out
0x7ff9e84000e0
air:~ jose$ g++ Foo.cpp main.cpp -I.
air:~ jose$ ./a.out
5
哪一个是正确的,为什么?
【问题讨论】:
-
如果您将
#includes 解析为单个可粘贴实体,对人们来说可能会更容易。 -
我觉得有趣的唯一部分是它甚至可以工作。
operator<<接受Bar::Foo const *,但通过print()模板您发送Bar::Foo * const(此时引用无关紧要)。取出模板并将指针直接发送到cout,看看两个工具链都给你什么。 更好是一样的。 -
无论哪个正确,您的代码都是错误(或至少明显可以改进)。您应该在命名空间
Bar中声明/定义operator<<,以便 Argument Dependent Lookup 找到它。 -
如果我直接将指针发送到 cout 而不是使用“打印”两个输出 5
-
@DavidRodríguez-dribeas:虽然我同意你的观点,运营商应该是
Bar命名空间的一部分,但这不是问题的根本原因。调用发生在全局命名空间中,因此名称查找应该找到 OP 的重载,并且比接受void const*的更喜欢它。
标签: c++ name-lookup