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::foobar will be checked against bar. But, the result of the expression &bar::foobar is of type void (foo::*)(), not void (bar::*)(). Now, after evaluation of &bar::foobar if you try to use that as a void (bar::*)() the compiler will try to perform the conversion of the pointer to member but will fail because foo is a protected base of bar, and in the context of main you 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:
class base {
protected: void f() {}
};
struct derived : base {
void foo( base& b ) {
b.f(); // Error
b.*(&derived::f)(); // OK
}
};
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 of bar directly, but somewhere inside bind code will be generated to apply the pointer to member to an instance of bar, and that requires the conversion.
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