When I compile the following snippet, I get a compiler error with clang, but not with g++/MSVC:
#include <string>
template<typename T> struct Const {
explicit Const(T val) : value(val) {}
T value;
};
template<typename T> struct Var {
explicit Var(const std::string &n) : name(n) {}
std::string name;
};
template<typename L, typename R> struct Greater {
Greater(L lhs, R rhs) : left(lhs), right(rhs) {}
L left;
R right;
};
template<typename L>
Greater<L, Const<int> > operator > (L lhs, int rhs) {
return Greater<L, Const<int> >(lhs, Const<int>(rhs));
}
template<typename R>
Greater<Const<int>, R> operator > (int lhs, R rhs) {
return Greater<Const<int>, R>(Const<int>(lhs), rhs);
}
Var<double> d("d");
int main() {
d > 10;
return 0;
}
The error reported is the following:
error: overloaded 'operator>' must have at least one parameter of
class or enumeration type
Greater<Const<int>, R> operator > (int lhs, R rhs) {
^
./val.h:31:24: note: in instantiation of function template specialization
'operator><int>' requested here
Greater<Const<int>, R> operator > (int lhs, R rhs) {
^
1 error generated.
which is about the operator function that is not used. If, instead, I write 10 > d instead of d > 10, then I get the same error about the other operator > function. The above compiles fine under gcc 4.4.6 and VS2012. What is my mistake ?
Thank you.
Clang is right: operator overloading requires at least one class or enum type parameter, otherwise the program is ill-formed (13.5/1). To see why this error even appears, we have to parse some more Standard legalese.
Recall the Holy Trinity of Name Lookup, Argument Deduction and Overload Resolution. The first step finds two overloaded
operator>
. The second step deduces template arguments for each version. You might think that the second overload would fall victim to the SFINAE rule (14.8.2), so that only the first survives to the third step. However, there is no substition failure (as in e.g. a missing nested typedef), but an illegal construct (see the earlier mentioned 13.5/1). That itself renders the program ill-formed (14.3/6)In 14.8.3 it is mentioned that this check on the deduced arguments happens before overload resolution, so your preferred operator has no chance of being selected.
As a C++03 work-around, you could define two friend non-template
operator>
inside yourVar<T>
class template. These would be injected into the surrounding (global, in this example) namespace as non-template functions with one class type parameter, so the above error should not occur.I must admit, I don't really know why clang complains here, it looks like a bug (of the compiler). Btw, clang 3.3 also exhibits the problem.
You can suppress it using SFINAE:
This looks like a bug in g++ and VS to me. In your example, your type
R
isint
(because the right-hand operand isint
). This then makes the signature of the functionGreater<Const<int>, R> operator > (int lhs, int rhs)
which is the same (parameter) signature as the builtinoperator<
for ints. Note that it has to consider both templates (and attempt to deduce types separately for each) when deciding whichoperator>
to use: It can't just look at one of them and decide to ignore the other one.