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" ?

Was it helpful?

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 for S<int>.

You said a.f(i) so it first needs to look for name f in A. It finds two fs. 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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top