I thought the const was only there to tell the compiler that the object being
passed is not changed and in the second case it is copied anyway
You are correct. Because in the second case it's copied anyway, and so the const
makes no difference to the caller, the standard defines that void f(const int x)
and void f(int x)
have the same signature. Hence they collide, you're trying to define the same function twice.
Because in the first case it isn't copied anyway, void f(const int &x)
and void f(int &x)
have different signatures. Hence they overload.
In your first case, it's forbidden to call the int&
version of f
with x2
as argument, because that would create a non-const reference to a const object without any explicit cast in sight. Doing that defeats the purpose of the const system (which is that if you want to break const-safety, you have to do so explicitly with a cast). So it makes sense to have const- and non-const overloads of functions with reference parameters.
In your second case, there's no relation between the const-ness of the source of a copy, and the const-ness of the destination. You can initialize a const variable from a non-const one, or a non-const one from a const one. This causes no problems and doesn't break const-safety. That's why the standard helpfully makes this clear by defining that your two "different" versions of f
are actually the same function.