#include
#include
struct B {
template::value>* = nullptr>
I actually think this is a gcc bug (84832 is closely related, though as Wakely notes it's possible that this should be a core language issue).
From [namespace.udecl]/15:
When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list, cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting). Such hidden or overridden declarations are excluded from the set of declarations introduced by the using-declarator.
Where a parameter-type-list is defined in [dcl/fct]/5:
The type of a function is determined using the following rules. The type of each parameter (including function parameter packs) is determined from its own decl-specifier-seq and declarator. After determining the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be “pointer to T”. After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. The resulting list of transformed parameter types and the presence or absence of the ellipsis or a function parameter pack is the function's parameter-type-list.
B::foo
and D::foo
have the same name ("foo"), parameter-type-list ([T]
), cv-qualification (none), and ref-qualifier (none). Hence, the derived one hides the base one.