I've encountered some code which I think should compile, but doesn't. So I'm hoping some of the local standards experts here at SO can help :-).
I basically have some code which resembles this:
#include <iostream>
template <class T = int>
class A {
public:
class U {
};
public:
U f() const { return U(); }
};
// test either the work around or the code I want...
#ifndef USE_FIX
template <class T>
bool operator==(const typename A<T>::U &x, int y) {
return true;
}
#else
typedef A<int> AI;
bool operator==(const AI::U &x, int y) {
return true;
}
#endif
int main() {
A<int> a;
std::cout << (a.f() == 1) << std::endl;
}
So, to describe what is going on here. I have a class template (A
) which has an internal class (U
) and at least one member function which can return an instance of that internal class (f()
).
Then I am attempting to create an operator==
function which compares this internal type to some other type (in this case an int
, but it doesn't seem to matter).
When USE_FIX
is not defined I get the following error:
test.cc: In function 'int main()':
test.cc:27:25: error: no match for 'operator==' in 'a.A<T>::f [with T = int]() == 1'
Which seems odd, because I am clearly (I think) defining a templated operator==
which should cover this, in fact if I just do a little of the work for the compiler (enable USE_FIX), then I no longer get an error. Unfortunately, the "fix" doesn't work generically, only for a specific instantiation of the template.
Is this supposed to work as I expected? Or is this simply not allowed?
BTW: if it matters I am using gcc 4.5.2.
The problem with const typename A<T>::U &x
is that U
is a dependent type and the compiler cannot deduce T
from the argument (this is one of the nondeduced context).
You could, for example, have two specializations of A
:
class X { };
class Y { };
class Z { };
template <> class A<X> {
public:
typedef Z U;
};
template <> class A<Y> {
public:
typedef Z U;
};
If you then call:
Z a;
a == 1;
what should the compiler deduce T
as? X
? Y
?
One solution in this particular case is to declare operator==
as a nontemplate friend inside of the class template:
template <class T = int>
class A {
public:
class U {
};
friend bool operator==(const U& x, int y) {
return true;
}
public:
U f() const { return U(); }
};
template <class T>
bool operator==(const typename A<T>::U &x, int y) {
return true;
}
Using this template, it is not permissible (or sometimes possible) to deduce the template parameter T
from the type of x
. It is what is known as a non-deducible context. (E.g. Somebody could specialize A
for a different parameter, say double
and make A<double>::U
a typedef for A<int>::U
.)
There is no workaround, you would have to explicitly specify the template parameter which for operator==
makes for ugly syntax.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With