enable_if : case of templated method of a template base inherited several times
Question
If I have a template base class with a template method :
template <typename T>
class S
{
public:
template <typename U>
void f(U p, typename enable_if<is_same<T, U> >::type*dummy = 0)
{
std::cout << p << std::endl;
}
};
For the example, I simplify the method : it must "exists" only if T == U
If A is this class:
class A : public S<int> {};
Then I have what I want:
int i = 1;
A a;
a.f(i);
compiles, but
double d = 2.0;
a.f(d);
doesn't compile : error: no matching function for call to ‘A::f(double&)’ It is the expected behavior.
Now let's A inherit from S<double>
also :
class A : public S<int>, public S<double> {};
Then the following code doesn't compile:
int i = 1;
A a;
a.f(i);
error: request for member ‘f’ is ambiguous error: candidates are: template<class U> void S::f(U, typename boost::enable_if<boost::is_same<T, U>, void>::type*) [with U = U, T = double] error: template<class U> void S::f(U, typename boost::enable_if<boost::is_same<T, U>, void>::type*) [with U = U, T = int]
I expected there is no ambiguity : f<int>
exists only for S<int>
In the compiler error, we can notice that T is known when this piece of code is compiled, but not U (U = U).
Any explanation or "workaround" ?
Solution
Try this:
a.S<int>::f(i);
...or alternatively inject the function into A
, e.g.
class A : public S<int>, public S<double>
{
public:
using S<int>::f;
using S<double>::f;
};
OTHER TIPS
You are right it only exists in S, but two times. Once for each type, int and double. So in your case you will need to specify exactly which function you want to call. The solution from Nim works just like that.
Others have given good workarounds, but I want to answer that other question you had
I expected there is no ambiguity :
f<int>
exists only forS<int>
.
You said a.f(i)
so it first needs to look for name f
in A
. It finds two f
s. In S<int>
and S<double>
. At name lookup time, it does not know yet that it later could have only selected S<int>::f
as a winner because S<double>::f
would be thrown away by SFINAE. The clear separation of name lookup and overload resolution and template argument deduction does not allow such intermingling.