Note that the following two functions have the same type and signature:
void foo1(int t) {} // foo1 has type 'void(*)(int)', and signature '(*)(int)'
void foo2(const int t) {} // Also type 'void(*)(int)', signature '(*)(int)'
(the const is not part of the function type or function signature). Similarly, a modifier (const or volatile) on the return type does not influence the function type or function signature.
However, in the function definition itself (not shown), the named variable t does maintain the const qualification in foo2.
There are many StackOverflow questions discussing why the return type of the function is not considered as part of the function signature (used for overload resolution).
However, I cannot find any StackOverflow question that asks why argument modifiers (const or volatile) are not part of the function’s type or signature. Also, I have looked directly in the C++11 standards document and find it difficult to unravel.
What is the rationale behind the fact that argument modifiers (i.e., const and volatile) are not part of a function’s type or signature?
ADDENDUM For clarity, from R.MartinhoFernandes’s answer below, I should clarify that in C++ (I think) the argument modifiers const and volatile are only ignored as part of the function type/signature if they are top-level modifiers – see that answer below.
From a caller’s perspective, there is no difference between
void foo(int)andvoid foo(int const). Whatever you pass to it will not be modified, regardless of the modifier: the function will get a copy.From an implementer’s perspective the sole difference is that with
void foo(int x)you can mutatex(i.e. your local copy) in the body, but you cannot mutatexwithvoid foo(int const x).C++ acknowledges these two perspectives. The caller’s perspective is acknowledged by making the two declarations
void foo(int);andvoid foo(int const);declare the same function. The implementer’s perspective is acknowledged by allowing you to declare a function asvoid foo(int x);but define it asvoid foo(int const x) { /*...*/ }if you want to make sure you don’t accidentally assign to the argument.Note that this only applies for top-level
const, i.e.constthat applies to the whole type. In things likeint const&orint const*the modifier only applies to a part of the type, as “pointer to (const (int))”, so it is not top-levelconst. Inint *consthowever, theconstagain applies to the whole type as in “const (pointer to (int))”.