Sign in to follow this  
Ryan_001

A problem with template member functions and inheritance

Recommended Posts

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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this