Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
174 views
in Technique[技术] by (71.8m points)

c++ - Is it OK for function prototypes and function implementation signatures to use const inconsistently?

I like to declare even value parameters as const where possible, and by searching SO, I found that that's not too uncommon. Like this:

int add(const int a, const int b)
{
    ...
}

But I'm wondering: const for values is an implementation detail of my function, not part of it's interface. So putting it into the prototype seems unnecessary.

This prototype for the above function seems to work just fine:

int add(int a, int b);

Yet I've heard about issues that e.g. declaring the main function's argc as const can lead to problems:

int main(const int argc, const char* const argv[])

So does that mean that int add(int a, int b) and int add(const int a, const int b) are not identical after all?

And if it's technically OK, is that something I should do? I could also leave out variable names in the prototype, but I don't, so maybe I shouldn't leave out const either?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...