A problem with template member functions and inheritance

Started by
7 comments, last by Zahlman 17 years, 6 months ago
I'm having a bit of a problem with inheriting template member functions. Here's what I've been able to boil it down to:

class Q {
	public:
	virtual int func () { return 4; }
	template <typename T> int func () { return func(); }
	};

class R : public Q {
	public:
	virtual int func () { return 5;	}
	};

int main (int argc, char* argv[]) {

	Q q;
	R r;

	q.func<long>();
	r.func<long>();    // error here
	
	return 0;
	}
In class Q the compiler can differentiate between func() and func<>() (the regular function and template one). But when inherited, the template memeber function seems to get lost somewhere. Now the funny thing is that if I replace class R with:

class R : public Q {};
it compiles fine. As well if I rename either of the functions it works as well. Currently I'm using VS express. So what I'm wondering, am I doing something wrong here? Or is this a compiler issue? *edited for typo
Advertisement
The compiler is doing the right thing. The name func is looked up in the scope of R and a matching function is found. Because a name has been found lookup does not continue to the scope of Q. Therefore the template function func in Q is said to be hidden by the func in R. Use a using declaration to bring it back into scope:
class R	:	public Q{	public:		using Q::func;		virtual int func () { return 5;	}};
Σnigma
So does this apply to all overloaded functions? As soon as I redefine one of them I have to use a 'using' to bring in all of them?
issue is inconsistency in class inheritance. you should do class templates.

Kuphryn
Quote:Original post by Ryan_001
So does this apply to all overloaded functions? As soon as I redefine one of them I have to use a 'using' to bring in all of them?


No, because it have nothing to do with overloading. Consider the following:
struct A{	void foo(int a)	{		}};struct B : A{	void foo(int a, int b)	{		}};

Some might think the following is valid:
B b; b.foo(5);

It isn't though, because, as Enigma explained, B's foo hides A's foo (it doesn't overload, it hides).
I think Ryan_001 meant that if you have a set of overloaded member functions in Base and override a subset of those member functions in Derived, do you have to use a using clause to make the entire set of overloaded member functions from Base visible in Derived. The answer to that is yes, for exactly the same reason.

Σnigma
Quote:Original post by Enigma
I think Ryan_001 meant that if you have a set of overloaded member functions in Base and override a subset of those member functions in Derived, do you have to use a using clause to make the entire set of overloaded member functions from Base visible in Derived. The answer to that is yes, for exactly the same reason.

Σnigma


I swear you're a mind reader. You said exactly what I was thinking better than I did.

Thanks for the help everyone (and very timely help I might add ;). I'm off to rename a few functions.

Btw, on a more theoretical note, does this not seem rather annoying? Is there plans to change this, or is this done for a reason I'm not seeing?
Name hiding is a sometimes-controversial topic. Herb Sutter states an argument for it in Exceptional C++:
Quote:Exceptional C++ by Herb Sutter, Item 34
For example, one might think that if none of the functions found in an inner scope were useable, then it could be okay to let the compiler start searching further enclosing scopes. That would, however, produce surprising results in some cases (consider the case in which there's a function that would be an exact match in an outer scope, but there's a function in an inner scope that's a close match, requiring only a few parameter conversions). Or, one might think that the compiler should just make a list of all functions with the required name in all scopes and then perform overload resolution across scopes. But, alas, that too has its pitfalls (consider that a member function ought to be preferred over a global function, rather than result in a possible ambiguity).

Σnigma
Why not just have it implicitly use the 'namespace' of all parent classes? This really is a special case AFAICT; people aren't really complaining about name-hiding in *other* contexts.

This topic is closed to new replies.

Advertisement