With this sample program I observe a different behavior in g++ and 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);
}
Compiling with clang++ and g++ produce different results:
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
Which one is correct and why?.
In this particular case, clang++ is correct.
The problem is how lookup is performed inside the template print
. In the expression inside print
the call to operator<<
is dependent. Name resolution for dependent names is handled in 14.6.4:
In resolving dependent names, names from the following sources are considered:
— Declarations that are visible at the point of definition of the template.
— Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.
In your case, the declaration of your operator is not visible at the point of definition of the template, since the header is included afterwards, and it does not live in any of the associated namespaces of the function arguments (namely ::std
for ::std::ostream
and ::Bar
for ::Bar::Foo*
), so it won't be found.
Now, there is an overload in ::std
that takes a void*
, and that will be found by Argument Dependent Lookup. The ::Bar::Foo*
will be converted to a void*
and the address will be printed.
That is, in a standard compliant compiler.
I forgot to add this here, and left it only in the comment, but it is important enough:
Always define the operators that apply to your types in the same namespace that holds the types on which they apply. Let Argument Dependent Lookup do it's magic for you. It was specifically designed to serve this particular purpose, use it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With