1

I'm curious about why the following doesn't compile:

#include <iostream>
#include <functional>

namespace Bar {
struct Foo {
  int x;
};
}  // Namespace                                                                                                                     

static bool operator==(const Bar::Foo& a, const Bar::Foo& b) {
  return a.x == b.x;
}

int main() {
  Bar::Foo a = { 0 };
  Bar::Foo b = { 1 };

  // The following line is OK
  std::cout << (a == b) << std::endl;

  // The following line is not OK
  std::cout << std::equal_to<Bar::Foo>()(a, b) << std::endl;
}

The compiler barfs in this case:

[test]$ g++ --std=c++11 -o test test.cc
In file included from /usr/include/c++/4.8/string:48:0,
                 from /usr/include/c++/4.8/bits/locale_classes.h:40,
                 from /usr/include/c++/4.8/bits/ios_base.h:41,
                 from /usr/include/c++/4.8/ios:42,
                 from /usr/include/c++/4.8/ostream:38,
                 from /usr/include/c++/4.8/iostream:39,
                 from test.cc:1:
/usr/include/c++/4.8/bits/stl_function.h: In instantiation of ‘bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = Bar::Foo]’:
test.cc:18:46:   required from here
/usr/include/c++/4.8/bits/stl_function.h:208:20: error: no match for ‘operator==’ (operand types are ‘const Bar::Foo’ and ‘const Bar::Foo’)
       { return __x == __y; }
                    ^
/usr/include/c++/4.8/bits/stl_function.h:208:20: note: candidates are:
...

The offending line doesn't compile even if I try another variant:

namespace Bar {
struct Foo {
  int x;
  bool operator==(const Foo& o) {
    return x == o.x;
  }
};
}  // Namespace

However, it seems like the following does compile:

namespace Bar {
struct Foo {
  int x;
};

static bool operator==(const Foo& a, const Foo& b) {
  return a.x == b.x;
}
}  // Namespace

What the heck is going on here?

1
  • ADL is not your friend. Commented Jul 31, 2015 at 0:48

1 Answer 1

5

Your first operator== is declared after the include of <functional>, so unqualified lookup for operator== in the template definition context of std::equal_to<Bar::Foo>::operator() will not find it. And it is not in Bar, the only associated namespace of Bar::Foo, so it's not found by ADL either.

The second, member, version barfs because equal_to's operator() takes both arguments by const reference, but the member function is not const.

The third version works because operator== is in the same namespace as Bar so it is found by ADL.

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

1 Comment

Thanks -- the member function not being const was a silly mistake. TIL about ADL -- this seems like magic!

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.