When you call a.foo(); , the compiler goes through overload resolution to find the best function to use. When it builds the overload set it finds

void foo() const

and

void foo()

Now, since a is not const , the non-const version is the best match, so the compiler picks void foo() . Then the access restrictions are put in place and you get a compiler error, since void foo() is private.

Remember, in overload resolution it is not 'find the best usable function'. It is 'find the best function and try to use it'. If it can't because of access restrictions or being deleted, then you get a compiler error.

In other words why does overload resolution comes before access control?

Well, let's look at:

struct Base { void foo() { std::cout << "Base

"; } }; struct Derived : Base { void foo() { std::cout << "Derived

"; } }; struct Foo { void foo(Base * b) { b->foo(); } private: void foo(Derived * d) { d->foo(); } }; int main() { Derived d; Foo f; f.foo(&d); }