Consider:
struct foo
{
void foobar(){}
};
struct bar : protected foo
{
using foo::foobar;
};
int main()
{
bar b;
b.foobar(); // Fine
&bar::foobar; // Not fine
}
I’m wondering what the rationale for letting using declarations expose the member, but not a pointer to it. In fact it would seem all using declarations that changes access level works for everything except taking the address of an exposed function.
UPDATE: An example which resembles my real use case better:
#include "boost/bind.hpp"
struct foo
{
void foobar() {}
};
struct bar : protected foo
{
using foo::foobar;
bar() { boost::bind( &bar::foobar, this )(); } // Crashes VS2008, GCC 4.1.1 fails to compile as it tries to go through foo*
};
int main()
{
bar b;
}
However, Mike Seymours’ explanation is spot on and explains why GCC fails. Thanks!
[I am assuming that in your program the code is:
void (bar::*p)() = &bar::foobar;]The problem is not that the using declaration does not bring the identifier into space, but the semantics of
&bar::foobar. I am considering (I would have done it if I had the time) refilling a Defect Report with this. There is already one such report.Basically the problem is that the using declaration brings the base function into scope for lookup in the derived type, and the access specifiers for the expression
&bar::foobarwill be checked againstbar. But, the result of the expression&bar::foobaris of typevoid (foo::*)(), notvoid (bar::*)(). Now, after evaluation of&bar::foobarif you try to use that as avoid (bar::*)()the compiler will try to perform the conversion of the pointer to member but will fail becausefoois aprotectedbase ofbar, and in the context ofmainyou don’t have access to that relationship.Note that I consider that to be a defect in the language for two reasons: first it breaks your code:
void (bar::*p)() = &bar::foobar;surprisingly fails to compile. Secondly, it breaks access protections in other cases:This problem is actually symmetric to yours, while in yours the surprising type of the address-of-member operation inhibits your use case when it shouldn’t, in this case it allows an usage that is against the intent of
protected.Related links:
After the comment on using
bind, it might not be the case that you are trying to convert the pointer to member to a pointer to member ofbardirectly, but somewhere insidebindcode will be generated to apply the pointer to member to an instance ofbar, and that requires the conversion.