1

I'm having trouble with a templated comparison operator for comparing instances of a type dependent on the template argument. I've been scouring the tubes for a while, including SO, and struggling to understand what I'm doing wrong. I believe it's an issue with dependent name lookup, but that's not helping me get the code working :-(

Here's a minimal testcase:

template<typename T>
struct Foo
{
  struct Bar {
     T t;
  };

  Bar b;
};


template<typename T>
inline bool operator<(const typename Foo<T>::Bar& b1, const typename Foo<T>::Bar& b2)
{ return b1.t < b2.t; }


int main()
{
  Foo<int> f1, f2;
  return (f1.b < f2.b?  0 : 1);
}

Compilation gives:

templated-comparison-op.cpp: In function ‘int main()’:
templated-comparison-op.cpp:20:20: error: no match for ‘operator<’ in ‘f1.Foo<int>::b < f2.Foo<int>::b’
templated-comparison-op.cpp:20:20: note: candidate is:
templated-comparison-op.cpp:13:13: note: template<class T> bool operator<(const typename Foo<T>::Bar&, const typename Foo<T>::Bar&)

For now I've got the comparison operator as a member of the template class, which works fine, so no urgency. I would like to understand what I'm missing here though; can anyone enlighten me?

Edit: That's not actually an accurate testcase; in the real code I extracted this case from, template class Foo is nested inside another class, and this is why the 'typename' keywords are required. As answers below state, in the code above 'typename' would be unnecessary.

Edit: I've replaced the original testcase with a new one highlighting the current problem, and also updated the question title, since I'm struggling to replicate the exact error I get in the real codebase. If there's a workaround for the issue in the testcase then perhaps that'll get the equivalent in real code closer to compilation, so still interested in pursuing this.

boycy
  • 1,473
  • 12
  • 25

3 Answers3

3

You don't need the typenames in the function declaration, since Foo<T> isn't a dependent type:

template<typename T>
bool operator<(const Foo<T>& f1, const Foo<T>& f2)
{ return f1.t < f2.t; }

(I'm not sure why they produce that particular error, but removing them fixes it).

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
3

The problem is that your operator< is not usable because the compiler cannot automatically find out what T is.

You can solve your problem by declaring a non-template operator<

template<typename T>
struct Foo
{
  struct Bar {
     T t;
  };

  Bar b;

  friend bool operator<(const Bar& b1, const Bar& b2)
  { return b1.t < b2.t; }
};

The operator< declaration is then found by argument dependent lookup for operator< for the expression x < y.

Alternatively you can put the operator< definition inside the definition Bar (but this doesn't really matter in this case, since Foo<T> is an associated class of Foo<T>::Bar).

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • Thanks Johannes, that works fine :-) I was unaware of that usage of 'friend' though; for anyone else wondering why it's there, SO has a relevant answer: http://stackoverflow.com/questions/381164/friend-and-inline-method-whats-the-point – boycy Oct 31 '11 at 10:09
2

Don't know if that's the problem, but the typename in the parameter list shouldn't be there. (If that's the problem, it's a horrible error message.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Duh, that was a stupidity of the minimal testcase on my part. The 'real' code I'm dealing with that I'd reduced to this has Foo as a nested type inside another class, which is why those are still there. not sure what SO-etiquette is in this case, since you answered my question perfectly, but I didn't /ask/ it correctly >. – boycy Oct 27 '11 at 15:53
  • 1
    Not sure myself, but I think if you edit the question, it would be OK. – James Kanze Oct 27 '11 at 16:49