2

In C and C++, parameters can be declared const when defining a function:

// without const
void foo(int i)
{
    // implementation of foo()
}

// with const
// const communicates the fact that the implementation of foo() does not modify parameter i
void foo(const int i)
{
    // implementation of foo()
}

From the caller's perspective, though, both versions are identical (have the same signature). The value of the argument passed to foo() is copied. foo() might change that copy, not the value passed by the caller.

This is all well, but one is allowed to use const also when declaring foo():

void foo(int i); // normal way to declare foo()

void foo(const int i); // unusual way to declare foo() - const here has no meaning

Why is const allowed by the C and C++ standards when declaring foo(), even though it is meaningless in the context of such a declaration? Why allow such a nonsensical use of const?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
user1387866
  • 2,834
  • 3
  • 22
  • 28

3 Answers3

3

const is a type qualifier: https://en.cppreference.com/w/cpp/language/cv

As such, they can be added to a type as part of the grammar itself. I suppose they didn't want to specify differently an argument and a variable. (it makes probably the implementation a little bit easier?)

Then the issue is that they don't participate to the signature when they refer to the argument itself (they are part of the signature when they refer for instance to the memory pointed by the argument), as you said in your question.

clang-tidy has a rule to remove the superfluous const: https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
1

There is no reason to forbid qualifiers on function parameters in non-definition declarations, and allowing it allows source code to keep identical declarations in both the definition and any non-definition declarations.

In a definition, const and other qualifiers have their normal effects, as in:

int foo(const int x)
{
    x = 3; // Not permitted.
}

Presuming we do not wish to lose this behavior, permitting qualifiers in definitions while prohibiting them in declarations that are not declarations would unnecessarily complicate the standard. Additionally, it means humans who copied the definition to paste it elsewhere as a non-definition declaration would have to make additional edits, and any software designed to collect external definitions from a source file to create a header file containing non-definition declarations would have to do additional parsing and manipulation to strip qualifiers (but only top-level qualifiers as in int * const p, where the const qualifies p, not those internal to types, as in const int *p, where the const, qualifies the type p points to, not p).

Generally, the C and C++ language do not prohibit “useless” things, such as adding a constant zero (which could arise from a combination of preprocessor macros, where some expression happens to evaluate to zero for certain selections of build options), isolated empty statements, and so on. These things are not of concern unless they contribute to the human propensity to make errors. For example, if adding zero always happened as a result of a mistake (so it never happened as a consequence such as mentioned above) then prohibiting it could have value. However, if there is no value to prohibiting something, then expending effort on prohibiting it is wasteful.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • _Generally, the C and C++ language do not prohibit "useless" things_ True. To take a related example, C does allow `const const const int i = 0;`. C++ does not allow it; I prefer the C++ standard in this respect, because I also consider `const const const int i = 0;` nonsense - but I concede that this is only a personal preference. – user1387866 Oct 22 '18 at 15:48
-2

First, const in lis of paramateres of functions isn't meaningless. Consider this code:

void foo(int i)
{
   i++;
   std::cout << i << "\n";
}

That's not possible if you add const. A parameter passed by value is a local variable for function if it is passed by value. Declaring it const you tell compiler that variable i cannot change its value during its lifetime.

Still not much of use? In C, maybe. In C++ that also means that you cannot call non-const methods of the type-class passed by value. Let's suppose that argument can be an object of a class-type and is an interface to some object that is stored outside of function. Then it does make sense that you declare that your function must leave that object "immutable".

Const doesn't participate in this particular case to form a function signature, so encountering those two variants in same scope or during name look-up leads to an ill-formed program. In other case it may define difference in categories of argument's value.

Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42
  • @EricPostpischil fixed it? Sorry, in my language they are arguments , parameter used only for templates. – Swift - Friday Pie Oct 21 '18 at 15:31
  • 1
    Many people do not distinguish them carefully, but, when we are discussing technical aspects of a programming language, it is good to be precise, and the C and C++ standards define them as such. – Eric Postpischil Oct 21 '18 at 15:32
  • @Swift - Friday Pie You are very confused, and out of topic. – user1387866 Oct 21 '18 at 15:34
  • @EricPostpischil I agree. Problem is that official translation of ISO standard doesn't follow that. Provided that a parameter and argument are translator enemy words :P Probably we have to sort out human languages first. – Swift - Friday Pie Oct 21 '18 at 15:34
  • 1
    @user1387866 No idea what do you mean. You called the `const` specifier here meaningless. It isn't. – Swift - Friday Pie Oct 21 '18 at 15:35
  • @user1387866: If you think this answer does not speak to the question you are asking, you need to explain why, because it is not clear. If you are intending to distinguish declarations and definitions, you should say so, in which case it could be pointed out the qualifier does alter the definition, and allowing it in the declaration provides consistency in the source code, thus making this answer clearly relevant. – Eric Postpischil Oct 21 '18 at 15:38
  • @Swift - Friday Pie Omg... I was talking about the fact that const is meaningless in a **declaration** such as `void foo(const int i);`. In a definition, though, it has a meaning. – user1387866 Oct 21 '18 at 15:38
  • 1
    @user1387866: Definitions are declarations. People could not know you intended to exclude definitions unless you stated so. – Eric Postpischil Oct 21 '18 at 15:40
  • 1
    @Eric Postpischil Of course I was meaning **non-defining declarations**, as my examples clearly showed. – user1387866 Oct 21 '18 at 15:42
  • @user1387866 well, compiler can't read our mind, and if both forms generate same signature, it would follow that. Definition and declaration may be in different compilation units, defining different rules for those is a dangerous step. We may omit parameter names in declaration and definition (if they aren't used), even that rule is consistent. – Swift - Friday Pie Oct 21 '18 at 15:43
  • @Eric Postpischil Jarod42 provided one valid explanation why meaningless const is allowed in declarations (I mean: non-defining declarations). If you can think of other valid reasons, please go ahead. – user1387866 Oct 21 '18 at 15:45
  • @user1387866 Simplicity of implementation? That's implied as stated in standard. Another is simplicity or code reading, maybe automate static analysis. Having unmatched prototype of function would be confusing and rise questions. – Swift - Friday Pie Oct 21 '18 at 15:48
  • @Swift - Friday Pie Could you please clarify? Are suggesting that `void foo(int)`and `void foo(const int)` have different signatures?! – user1387866 Oct 21 '18 at 15:48
  • @Swift No, but human reading that code would see a difference, right? Or if they would search for one awhile there is another. – Swift - Friday Pie Oct 21 '18 at 15:49