Additional notes (September, 2012):
Tomasz KamiĆski pointed out three additional motivating examples:
struct Very_base { int a; }; struct Base1 : Very_base {}; struct Base2 : Very_base {}; struct Derived : Base1, Base2 {} int main() { Derived d; int Derived:: * a_ptr = &Derived::Base1::a; //error: Very_base ambiguous despite qualification };
Also:
struct Base { int a; }; struct Derived : Base { int b; }; template<typename Class, typename Member_type, Member_type Base:: * ptr> Member_type get(Class &c) { return c.*ptr; } void call(int (*f)(Derived &)); int main() { call(&get<Derived, int, &Derived::b>); // Works correctly call(&get<Derived, int, &Derived::a>); // Fails because &Derived::a returns an int Base::* // and no conversions are applied to pointer to member // (as specified in 13.4.3 [temp.arg.nontype] paragraph 5) call(&get<Base, int, &Derived::a>); //Template function is instantiated properly but has invalid type }
Finally:
struct Base { int a; }; struct Derived : private Base { public: using Base::a; //make a accessible }; int main() { Derived d; d.a; // valid int Derived::* ptr = &Derived::a; // Conversion from int Base::* to int Derived::* // is ill-formed because the base class is inaccessible }