This is interesting.
Per the current rules*, it appears that the intent is for foo
to remain a member of the base, rather than introducing an actual member of B
.
That's despite the fact that overload resolution can now find the member in B
:
[namespace.udecl/15]
: [Note: For the purpose of forming a set of candidates during overload resolution, the functions that are introduced by a using-declaration into a derived class are treated as though they were members of the derived class ([class.member.lookup]). In particular, the implicit object parameter is treated as if it were a reference to the derived class rather than to the base class ([over.match.funcs]). This has no effect on the type of the function, and in all other respects the function remains a member of the base class. — end note]
That's also despite the fact that, in code, B::bar
can refer to that member (i.e. it doesn't have to be spelled A::bar
):
[expr.prim.id.qual/2]
: A nested-name-specifier that denotes a class, optionally followed by the keyword template
([temp.names]), and then followed by the name of a member of either that class ([class.mem]) or one of its base classes, is a qualified-id; [class.qual] describes name lookup for class members that appear in qualified-ids. The result is the member. The type of the result is the type of the member. [..]
But the actual type of the member is therefore void (A::*)(int)
.
There is no rule permitting conversion to void (B::*)(int)
, even one specific to members introduced in this manner (and obviously such a conversion couldn't be valid in general).
Therefore, I believe that Visual Studio is in error.
* I'm citing the current draft, for convenience, but have no reason to believe that this rule has changed recently; both GCC and Clang reject the code in all of C++11, C++14 and C++17.
As an aside, this doesn't actually compile with the latest version of Visual Studio, either:
<source>(29): error C2672: 'B::baz': no matching overloaded function found
<source>(29): error C2893: Failed to specialize function template 'void B::baz(void)'
<source>(21): note: see declaration of 'B::baz'
<source>(29): note: With the following template arguments:
<source>(29): note: 'M=void A::foo(int)'
So, perhaps they've fixed the bug since your version. There is also a compatibility mode in VS that may be to blame.