First, all definitions that you provide are syntactically correct. If they compile, then they are correct in syntax.
The const qualifier for parameters has only one purpose: to prevent the body of the function from changing const arguments.
In the specific case of your sample code, the Foo::bar method does not change the arguments, so using the const qualifier has no effect.
However, in all cases, you can use const by default and remove it only in situations where you want to allow changes. Therefore, applying it to Foo::bar parameters is a good idea. I think this is good practice, although I will admit that I rarely use it because it carries noise, which can reduce readability.
Another thing to consider is that for primitive types or, more precisely, types that are not pointers or do not contain pointers, changing the argument passed by the value (i.e. not by reference) will not have no side effect: the parameters of these types really act as initialized local variables (which can be convenient, but can also be confusing). For pointers, any modification of pointy data will flow into the outside world. This is another good reason to use the const qualifier on both the pointer and the pointed part of the type.
In general, using the const qualifier as much as possible will help make the code less error prone and also help the compiler optimize the resulting program.
Using a reference for these types, however, should not cause any significant changes if these types describe the values ββset in the CPU register (which is usually the case),
So, all three versions of the method should come down to the same generated assembler.
In the particular case of primitive return types, this does not matter. the return value can be converted back and forth to const .
Others also mentioned the const qualifier's interest in the function itself. Although from the area of ββthe original question I will also say that it is really better, when possible (for example, for Foo::bar ), to qualify a function as const .