I used to believe that 'typedef' is not automatically inherited. But the code snap below suggests something different.
#include <iostream>
#include <type_traits>
struct A
{
typedef int X;
};
struct A_
{
typedef char X;
};
struct B : A {};
struct B_ : A, A_ {};
template< typename ... Ts >
using void_t = void;
template< typename T, typename = void >
struct has_typedef_X : std::false_type {};
template< typename T >
struct has_typedef_X< T, void_t<typename T::X> > : std::true_type {};
int main()
{
std::cout << std::boolalpha;
std::cout << has_typedef_X<A>::value << std::endl;
std::cout << has_typedef_X<A_>::value << std::endl;
std::cout << has_typedef_X<B>::value << std::endl;
std::cout << has_typedef_X<B_>::value << std::endl;
return 0;
}
The output is 'true true true false'.
But in my point of view, 'has_typedef_X<B>::value
' giving 'true' implies that in struct B, X is 'typedef'ed.
So if anyone can please explain this problem or correct me?
A online version is available at http://melpon.org/wandbox/permlink/iwZ6eZ3PoBPgyFBj [URL corrected]
Nested type names (i.e. member types) of parents are visible in the scope of a derived class and accessible as long as the access specifier of is not private. If there are multiple types with the same name from different base classes, then the unqualified name is ambiguous.
The most relevant standard quotes that I found regarding this are:
[class.nested.type] §1
Type names obey exactly the same scope rules as other names. [...]
[class.member.lookup] §9
[ Note: A static member, a nested type or an enumerator defined in a base class T can unambiguously be found even if an object has more than one base class subobject of type T. [...]
In fact, an example of using this is the standard which specifies that the iterators of standard containers inherit std::iterator
template, which contains nothing but nested type names. The whole point of the inheritance is to get these nested type names to the iterator. (This example will become outdated in the next standard version (c++17), where std::iterator
is proposed not to be used anymore.)
X
is in scope for both B
and B_
, the issue with B_
is that B_::X
is ambiguous, so template deduction fails for the truthy has_typedef
leaving the false one as the only match.
Since the name X is ambiguous due to being defined in two base classes, this causes template deduction to fail for B_
in has_typedef
.
Your belief that typedefs are not inherited might have come from some C++ specialties during unqualified name lookup, where base classes are not considered. See Propagating 'typedef' from based to derived class for 'template'
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