Why is this happening? Are int& and int two different types?
It is wrong to think that passing a variable name to a function means that the argument has the exact same type as the variable.
References in C++ are not exactly distinct types. In particular an expression, such as the id-expression naming the variable used as a function argument, never has a reference type. If you name a reference variable as an id-expression, then the id-expression has the referenced type of the variable's reference type.
The point of references in C++ is that they behave in expressions exactly as if you had named the object that the reference is bound to directly. So whether you write f(a) or f(b) the result should be exactly the same.
Therefore the fact that b's type is reference-qualified can't matter to overload resolution. Overload resolution only knows that the argument is of type int and that it is an lvalue expression (i.e. an expression referring to an object instead of an abstract value).
Both function overloads are then viable and there isn't any clear preference one would have for one over the other, so the rules say that such an overload attempt between a reference and non-reference parameter in which the conversion sequences are equally ranked (identity conversion sequence here in both cases), are ambiguous.
If so, why the compiler do not detect the problem in source.cpp where the functions are defined?
The compiler will detect the problem in main.cpp, because the problem will force it to fail compilation. If your compiler didn't complain, then that's a bug in the compiler.
There is no issue in source.cpp because there is absolutely nothing wrong with just defining the two function overloads. The only problem is that calling them with an int lvalue as argument is ambiguous. If you tried to pass something else, e.g. a long, then only one of the two overloads would be viable and could be chosen. There is nothing in general wrong with having the two overloads.
fcan be called both with a copy ofband also with a reference tob. Both are valid here. Thus inf(b);the compiler is not able to tell which overload is the intended one.f(int a)can be called withint&and a copy will be passed to it.