Bug 40804 - STL: operator>= for pair "hides" general operator>= from std::rel_ops
Summary: STL: operator>= for pair "hides" general operator>= from std::rel_ops
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.4.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-07-19 09:07 UTC by Andrea
Modified: 2009-07-19 18:36 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Preprocessed file to reproduce the error. (2.76 KB, application/x-gzip)
2009-07-19 09:11 UTC, Andrea
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Andrea 2009-07-19 09:07:41 UTC
The fact that std::pair has operator>= defined in namespace std "hides" oprator>= defined in namespace std::rel_ops, for all classes.

operator>= for pairs is defined in <bits/stl_pair.h>, and it is in namespace std;

This only happens when " >= " is used from std, as in the case of "greater_equal".

I use >= as an example, the same happens for (<=, >, .....)

I've tested this behavior with gcc 4.4.0 (on Fedora 11), gcc 4.3.X and 3.4.X from cygwin.

This small c++ program fails with (compiled as g++ -c foo.cpp)
(If I add -Wall, it reports about ok and bad not being used).

In file included from /usr/lib/gcc/i586-redhat-linux/4.4.0/../../../../include/c++/4.4.0/functional:51,
                 from foo.cpp:3:
/usr/lib/gcc/i586-redhat-linux/4.4.0/../../../../include/c++/4.4.0/bits/stl_function.h: In member function ‘bool std::greater_equal<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = A]’:
foo.cpp:20:   instantiated from here
/usr/lib/gcc/i586-redhat-linux/4.4.0/../../../../include/c++/4.4.0/bits/stl_function.h:239: error: no match for ‘operator>=’ in ‘__x >= __y’


#include <utility>
#include <functional>

using namespace std;
using namespace std::rel_ops;

struct A
{
  bool operator<(const A &) const;
};

void foo1()
{
  bool ok = A() >= A(); // just to check rel_ops is actually included
}

void foo2()
{
  greater_equal<A> ge;
  bool bad = ge(A(), A());
}

The only way to make it compile so far is to add

namespace std
{
  namespace rel_ops
  {
  }
  using namespace rel_ops;
}

so that rel_ops::operator>= is found by "greater_equal".

If I only add 

using namespace std::rel_ops;

in my C++ source code, it is not enough, since (I think) gcc chooses (while parsing greater_equal) the operator>= defined in std (the only one available at that time), and when an other one is added later (from rel_ops) it is too late.

Alternatively, if I move operator>= for pair into std::rel_ops everything works.

I am not sure where is the root of the problem, but my thoughts are

1) why do we need an operator >= for pair? is it not enough the one for all <T>?
2) why is operator>= for pair in std and not in std::rel_ops?
3) is gcc correct in ignoring operator>= from rel_ops?
Comment 1 Andrea 2009-07-19 09:11:55 UTC
Created attachment 18227 [details]
Preprocessed file to reproduce the error.

Filed obtained with 

g++ -E foo.cpp -o foo.i

to reproduce the issue.
Comment 2 Richard Biener 2009-07-19 10:16:41 UTC
using namespace std;
using namespace std::rel_ops;

is the problem.  You are changing name-lookup results.  With arbitrary
using directives you can get to arbitrary name-lookup results.
Comment 3 Andrea 2009-07-19 17:29:26 UTC
I have removed one of the "using" and still get the same problem:

#include <utility>
#include <functional>

using namespace std::rel_ops;

struct A
{
  bool operator<(const A &) const;
};

void foo1()
{
  bool ok = A() >= A(); // just to check rel_ops is actually included
}

void foo2()
{
  std::greater_equal<A> ge;
  bool bad = ge(A(), A());
}

An alternative way is to replace the "using namespace std::rel_ops;" with

using std::rel_ops::operator>=;

but this means I have to repeat it for every operator I need.

Is there an other way to make all operators defined in rel_ops available?
Comment 4 Richard Biener 2009-07-19 17:35:13 UTC
Use it in struct A:

struct A
{
  using std::rel_ops;
  bool operator<(const A &) const;
};

ADL (also known as Koenig lookup) will then find it for arguments of type A.

it's really not a good idea to globally import pieces of the standard namespace
(using std; is an execption because it's just used so widely).
Comment 5 Andrea 2009-07-19 18:06:10 UTC
Thanks for your detailed answer.
Comment 6 Paolo Carlini 2009-07-19 18:36:13 UTC
In general, I recommend being wary of anything having to do with rel_ops: most of the authors of the original C++03 standard have today a very low opinion of it, essentially consider it irreparably broken.