Q:

Why is this allowed?

So I know it is disallowed to have functions with the same parameters and names:
int a(int b) {
    return b;
}
int a(int b) {
    return b;
}

int main() {
    int c = a(4);
}

This above won't compile. But then I got thinking, what if I passed one by reference, and one by value?
int a(int b) {
    return b;
}
int a(int& b) {
    return b;
}

int main() {
    int c = a(4);
}

The above does compile, I guess because you can't pass 4 to by reference, so it assumes you want the first a, which means the compiler can distinguish which function you want to call. If I then change main to this:
int main() {
    int c = a(4);
    a(c);
}

It will fail to compile, I assume because c can be passed to either function, so the compiler doesn't know which function to call.
But what about... THIS?
int a(const int& b) {
    return b;
}
int a(int& b) {
    return b;
}

int main() {
    int c = a(4);
    a(c);
}

This does compile. Why? I expected it to not, because c can be passed to both the first and second a. Is there some misconception I have?
My question specifically is, how come this (code below) does not compile, and the final one does?
int a(int b) {
    return b;
}
int a(int& b) {
    return b;
}

int main() {
    int c = a(4);
    a(c);
}

If I was the compiler, and I could choose which function to call based how close the parameters matched, for the call a(c), I could choose from both the first and second. Is there any reason that the first or second a cannot be chosen from in this example?

A:

The process of choosing the correct function to use from a function call is called Overload Resolution. When a function is called, the compiler searches for all functions with that name (overloads) and compiles them into an overload set. Simply put, a best match is chosen by picking the functions that require the least conversions as possible from their parameters.
These are the two functions compiler chooses from a(c):
int a(const int& b);
int a(      int& b);

The second overload is chosen because the first overload requires a const-qualification. The variable with which you called the function with, c, is non-const, so it is a perfect match for the second overload and can be bound to the non-const reference.

