2
#include <functional>
#include <iostream>

struct A {
    friend bool operator==( const A & a, const A & b ){
        return true;
    }
};

namespace {
    bool operator!=( const A &a, const A & b){
        return !(a==b);
    }
}

int main(int argc, char **argv) {
    std::not_equal_to<A> neq;
    A a;

    bool test = neq(a, a);

    return test ? 0 : 1;
}

This fails on CC (SunOs Compiler) with:

Error: The operation "const A != const A" is illegal.
"tempcc.cpp", line 16:     Where: While instantiating "std::not_equal_to<A>::operator()(const A&, const A&) const".
"tempcc.cpp", line 16:     Where: Instantiated from non-template code.

And on g++ with:

/usr/local/include/c++/3.3.2/bits/stl_function.h: In member function `bool std::not_equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = A]':
tempcc.cpp:16:   instantiated from here
/usr/local/include/c++/3.3.2/bits/stl_function.h:183: error: no match for 'operator!=' in '__x != __y'

However if I remove the line #include <iostream> it compiles and runs just fine. Anyone dare to explain this?

elmo
  • 1,189
  • 1
  • 10
  • 35
  • 1
    Doesn't work at all on [IdeOne](http://ideone.com/Ah6Hd) even with `#include ` removed. – Seth Carnegie Dec 13 '11 at 12:02
  • Does this help: http://stackoverflow.com/questions/2525984/template-access-of-symbol-in-unnamed-namespace – Seth Carnegie Dec 13 '11 at 12:06
  • Both of the above are from are from SunOS. I tried it also on AIX with g++ and results are the same (with iostream it doesn't compile, without it does). I will try to run this on Linux to see what it does if noone else will try that before me. – elmo Dec 13 '11 at 12:07
  • @Seth It might be. But then removing the "namespace{}" solves the issue also. And I don't think it should if it was the case you linked. I have to think about that more. – elmo Dec 13 '11 at 12:11
  • Tried that before. Doesn't change a thing. But it seems that if not the same they are closely related issues. – elmo Dec 13 '11 at 12:20
  • It works if you replace `` by `` in GCC, so the problem must come from one of the other includes in `functional`... – Kerrek SB Dec 13 '11 at 12:55
  • what happens, if you explicitly instantiate std::not_equal_to inside of the anonymus namespace ? – ch0kee Dec 13 '11 at 13:02
  • @ch0kee Don't hold me to that, because I did a lot of different versions, but I think that one compiled as long as the namespace was unnamed. And for changing header it seems reasonable, because it appears I have here a bit less standard implementation of STL which might cause it to compile (still don't know why). – elmo Dec 13 '11 at 13:09
  • I think I found the answer. See below. – Kerrek SB Dec 13 '11 at 13:26

2 Answers2

0

According to Comeau, this isn't legal either way - the fact that the compiler builds it when you don't #include <iostream> may be the actual bug, not the other way around (or at least a disagreement in interpretation):

"stl_function.h", line 99: error: no operator "!=" matches these operands
            operand types are: const A != const A
    bool operator()(const _Tp& __x, const _Tp& __y) const { return __x != __y; }
                                                                       ^
          detected during instantiation of "bool
                    std::not_equal_to<_Tp>::operator()(const _Tp &, const _Tp
                    &) const [with _Tp=A]" at line 19 of "ComeauTest.c"

"ComeauTest.c", line 10: warning: function "<unnamed>::operator!=" was declared but
          never referenced
      bool operator!=( const A &a, const A & b){
           ^

It makes sense that this doesn't build - placing operator!= in an unnamed namespace still puts it in a different namespace than ::, and I'm not entirely sure why g++ builds it without the iostream include - if you look at the preprocessor output from g++ it hasn't done anything hinky to reorder code or any such nonsense, and of course iostream doesn't define operator!= for A.

I do not have my copy of the C++ standard handy, but this link from IBM at least validates the claim that unnamed namespaces don't mix that well with the global one, explaining why you can't find the operator!= you've defined.

You also might find some helpful information in Anonymous Namespace Ambiguity.

Community
  • 1
  • 1
Nick Bastin
  • 30,415
  • 7
  • 59
  • 78
  • 1
    After some investigation and what Seth put in comments above made me believe that it is actually the case that the bug is that it actually builds. So nothing new, but I think this answer is closest to short explanation of the problem. – elmo Dec 13 '11 at 13:11
0

The problem is that <functional> also pulls in several templates from from tuple and utility that interfere with the lookup.

If you were to remove this, e.g. by only including <bits/stl_function.h> in GCC, then there is no problem, although is is of course not a real solution. I suppose you cannot get around either implementing your own operator!=() or adding an explicit specialization for std::not_equal_to if you require the predicate.

However, if you don't need to use the not_equal_to predicate, you can circumvent the problem entirely by removing all your custom code and adding the following:

#include <utility>
using namespace std::rel_ops;

bool test = a != a;
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Then why if I did not create this template by hand I got "!= is illegal operation"? The problem grew from exactly the problem of not having this template by default (I have a class with only operator== defined). Besides then mine in unnamed namespace should be just ignored and the one from bits/stl_relops.h should be used, shouldn't it? – elmo Dec 13 '11 at 13:41
  • Sorry, my argument was wrong. It is actually a *different* set of templates that interfere. However, you can take advantage of the predefined `rel_ops` simply by adding `using namespace std::rel_ops;` to your code (from ``). – Kerrek SB Dec 13 '11 at 14:08