9

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?.

9
  • It might be easier for people if you resolved the #includes to a single pasteable entity. Commented Apr 12, 2013 at 15:54
  • The only part of this I find interesting that it even works. The operator<< takes a Bar::Foo const *, but through the print() template your sending a Bar::Foo * const (the reference is immaterial at that point). Take out the template and just send the pointer-direct to cout and see what both toolchains give you. The better be the same. Commented Apr 12, 2013 at 16:02
  • Whichever is right, your code is wrong (or at least clearly improvable). You should declare/define that operator<< inside the namespace Bar, so that Argument Dependent Lookup will find it. Commented Apr 12, 2013 at 16:07
  • if i send directly the pointer to cout instead of using "print" both output 5 Commented Apr 12, 2013 at 16:07
  • @DavidRodríguez-dribeas: While I agree with you that the operator should be part of the Bar namespace, this is not the root cause of the issue. The call occurs in the global namespace, so name lookup should find the OP's overload and prefer it over the one accepting a void const*. Commented Apr 12, 2013 at 16:14

1 Answer 1

13

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Turns out it had already been reported: gcc.gnu.org/bugzilla/show_bug.cgi?id=51577

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.