I came across the following situation in one of my projects, where a base class has a function template, which is hidden by a non-templated function in a derived class template. Further down the class hierarchy, the non-templated function is explicitly bringing the function into the scope via a using directive.
Here's a simplified example code:
class Base
{
public:
template<typename T> const T& get() const;
};
template<typename T> class Derived : public Base
{
private:
using Base::get;
public:
const T& get() const;
};
template<typename T> class MoreDerived : public Derived<T>
{
public:
using Derived<T>::get; // <-- this causes the problem
const T& call_get() {
return get();
}
};
template class MoreDerived<int>;
Godbolt: https://godbolt.org/z/5MQ0VL
The above code fails on GCC and Clang with errors like:
<source>:15:28: error: 'template<class T> const T& Base::get() const' is inaccessible within this context
15 | template<typename T> class MoreDerived : public Derived<T>
MSVC and ICC accept this code without complaints.
I'm wondering, why the compilers complain about Base::get<T>
while there is a public overload Derived<T>::get
available?
Removing the private using Base::get
from Derived<T>
leads to warnings about hiding functions from the base class. So this is unfortunately also not an ideal option.
Without the using Derived<T>::get
, calls to get
have to be qualified within MoreDerived
as it would not be a dependent name otherwise.
Any ideas, what I'm doing wrong here?
I believe what applies here is [namespace.udecl]/17:
In a using-declarator that does not name a constructor, all members of the set of introduced declarations shall be accessible. In a using-declarator that names a constructor, no access check is performed. In particular, if a derived class uses a using-declarator to access a member of a base class, the member name shall be accessible. If the name is that of an overloaded member function, then all functions named shall be accessible. […]
(emphasis mine) in combination with [namespace.udecl]/19:
A synonym created by a using-declaration has the usual accessibility for a member-declaration. […]
The using declaration in MoreDerived
creates a synonym for Derived::get
which itself is a synonym for the overload set consisting of the member function Derived::get
and the member function template Base::get
. The latter is not accessible at the point of the using declaration in MoreDerived
(because it is private in Derived
). Thus, GCC and Clang are correct, this code should not compile. Moving the using declaration in Derived
from the private to the public part, for example
template<typename T> class Derived : public Base
{
public:
using Base::get;
const T& get() const;
};
resolves the issue…
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With