Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moving Template Method to Derivative Breaks Compilation

Given the following code:

template<typename T>
class A
{
public:
   T t;
};

class B
{
public:
   void foo(int i) {}

   template<typename T>
   void foo(A<T>& a) {}
};

int main()
{
   A<int> a;
   B      b;

   b.foo(a  );
   b.foo(a.t);
}

This compiles and works fine; the correct overloaded versions of B::foo() are chosen and called for a and a.t.

Now I introduce a new class C which derives from B and move the template version of ::foo() out of B and into C:

template<typename T>
class A
{
public:
   T t;
};

class B
{
public:
   void foo(int i) {}
};

class C: public B
{
public:
   template<typename T>
   void foo(A<T>& a) {}
};

int main()
{
   A<int> a;
   C      c;

   c.foo(a  ); // Fine
   c.foo(a.t); // Error
}

And now the code won't compile anymore. Visual Studio 2005 is stating:

error C2784: 'void C::foo(A<T> &)' : could not deduce template argument for 'A<T> &' from 'int'

In fact, calling C::foo() with any int value results in this error. It almost seems like the method overload for int is being hidden by the template overload.

Why is this happening? Is it some issue with Visual Studio 2005's compiler? Unfortunately, I cannot test it on any other compiler right now.

Any information is appreciated.

like image 932
Torben L. Avatar asked Sep 24 '12 16:09

Torben L.


3 Answers

It almost seems like the method overload for int is being hidden by the template overload.

Exactly! You need to add a using declaration to class C:

class C: public B
{
 public:
  using B::foo;
  template<typename T>
  void foo(A<T>& a) {}
};

When you declare a member function in a derived class, all member functions in the base class with the same name are hidden. See §3.3.10/3 of ISO/IEC 14882:2011:

The declaration of a member in a derived class (Clause 10) hides the declaration of a member of a base class of the same name; see 10.2.

like image 136
Joseph Mansfield Avatar answered Nov 07 '22 00:11

Joseph Mansfield


It's hiding, no overloading. Use

class C: public B
{
public:
   using B::foo;
   template<typename T>
   void foo(A<T>& a) {}
};
like image 36
ForEveR Avatar answered Nov 07 '22 01:11

ForEveR


Correct, the base function is hidden. That's actually the proper term for it. Add using B::foo; to the class definition of C to unhide it.

like image 1
Kerrek SB Avatar answered Nov 06 '22 23:11

Kerrek SB