It's not OK for the function type to differ, but you need to know what is part of the function type and what isn't. In your case, the const
for the parameters is not significant, so the function type is the same, although the declaration looks like it differs from the definition.
In your case it's
8.3.5 Functions [dcl.fct]
5 A single name can be used for several different functions in a single scope; this is function overloading (Clause 13). All declarations for a function shall agree exactly in both the return type and the parameter-type-list. The type of a function is determined using the following rules. The type of each parameter (including function parameter packs) is determined from its own decl-specifier-seq and declarator. After
determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively. After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. The resulting list of transformed parameter types and the presence or absence of the ellipsis or a function parameter pack is the function’s parameter-type-list. [ Note: This transformation does not
affect the types of the parameters. For example, int(*)(const int p, decltype(p)*)
and int(*)(int, const int*)
are identical types. — end note ]
As it seems, it need some explanation, so here we go: The important sentence in our case is: After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type.
This means that all top-level cv-qualifier are remove. To explain what top-level means, I'll write types in an illegal way to emphasize what a const
refers to:
const int
= (const (int))
-> this is a top-level const
const int*
= ((const (int))*)
-> not top-level, it's at the second level
const int* const
= (((const (int))*) const)
-> the second const
is at top-level
const int&
= ((const (int))&)
-> not top-level
I hope this clears some misconceptions about function types up.
For your other questions: I'd advise to keep the declaration and the definition identical, as it might confuse people (like evidenced by this question ;).
For the example of main
that you gave:
int main( const int argc, const char* const argv[] )
is, according to the above quote from the standard, equivalent to:
int main( int argc, const char* const* argv )
so the added const
for argv
does not end up as a top-level const
which is removed and it's therefore an ill-formed function type for main
, which expects:
int main( int argc, char** argv )
You last question about leaving out the parameter names: I wouldn't do it because to me, they are part of the documentation of the function. They communicate the intent and the semantics of the function (if you choose them wisely).