const parameter - c++

In C++, does the following make sense?
main()
{
int a=10;
fun(a);
}
void fun(const int a)
{
...
}
I can see a program similar to this compile but have linker issues. I just wanted to confirm if assigning a non const var to a const var is apt in C++.

Yes, it is OK.
a cannot be reassigned in fun(), exactly as if it would have been declared that way:
void fun(int param)
{
const int a(param);
...
a = 5; // this is illegal and won't compile.
}
As it is passed by copy, there is no impact on main()'s a anyway. Even if fun()'s a was declared as non-const and modified.

In a function declaration the top level1 const is stripped out by the compiler, while it is kept in the definition.
The reason is that the top level element is copied, and from the point of view of the caller it does not really matter whether the copy is constant or not, so on that end const-ness is not an issue. On the other end, in the definition of the function the argument cont-ness is maintained as it can help the compiler detect unintended modifications of the argument inside the function.
So basically:
void foo( int );
void foo( const int ); // redeclaration of the same function
void foo( const int x ) {
++x; // error: x is const!!
}
In the code above there are two exactly equivalent declarations of foo (the compiler will remove the const from the declaration), and a single definition. Because the in the signature of foo in the definition x is declared as a constant integer, the compiler will complain if you try to increment it.
Some people will use the const in the definition to get the compiler to flag ++x as erroneous, but it is not common. On the other hand, whether the argument is declared as int or const int, for the caller they are the same.
1 Note that this only applies to the top level const, which is applicable to arguments passed by value and pointers, but never to references (a reference is always const: you cannot reassign the reference). So these are different function declarations:
void f( int& );
void f( int const & );
void f( int* ); // equivalent to void f( int * const )
void f( int const * ); // equivalent to void f( int const * const )

It would make sens if you added return types to your functions and had forward-declared fun before you called it (or reversed the order of your functions in that compilation unit).
For a plain int, it doesn't change anything for the caller - the called function can't change the value of that variable in the caller regardless of that qualifier. But for the called function, the parameter is const, so it can't be modified - that makes a difference, not sure if that generally "usefull" or not.
Now consider this:
int foo(int& a);
int bar(int const& a);
Those are two different beasts. bar can only read a, and can take either a plain int or a const int (or a const int&).
foo, on the other hand, can change a if it sees fit, and cannot take a const.
See the Const correctness entry in the C++FAQ Lite for more on this, including information about how this applies (or not) to const-pointers, pointers-to-const and const-pointer-to-const.

It doesn't make much sense because what you get in the function is a copy of the variable, not the variable itself. But this is legitimate.

The "assignment" is ok - a in fun is a new variable which is kept constant inside fun.
But fun should have a return type, i.e. void.
And there should be a declaration of fun before using it in main.

You can assign a non-const to a const

Related

Are some usages of const only really useful when returning or passing things by reference? Or do they have subtle uses I'm not seeing

I've read about the various places to put const. Some usages seem clearly useful to me. Others however evade me. It would be really helpful if someone could confirm or correct my understanding as I explain my mental model of things.
These are the same. I'm not sure I understand why this would ever be useful, though. Does it perhaps allow one to initialize const int variables with a function, which in turn allows some compiler optimizations?
const int foo();
int const foo();
These are the same. The returned pointer cannot be used (via dereferencing) to change the values pointed to.
const int * foo();
int const * foo();
This means the returned pointer itself cannot be changed. But, why would it matter if the caller essentially decides to ignore the returned pointer and set it to something else? Is this only really useful if the pointer is returned by reference?
int * const foo();
These are the same. It means you can only pass in const ints, which allows the compiler to optimize things.
int foo(const int foo);
int foo(int const foo);
This means the passed-in pointer cannot be changed. I'm wondering here too, why would it matter unless the pointer is being passed in by reference?
int foo(int * const foo);
This (as a member function) guarantees that the function won't change the state of the object. Also, if the object itself is declared const, then it will only be able to call such functions.
int foo(int foo) const;
const int as return type is pointless, because in an expression the type of a non-class prvalue result of a function call will be stripped of its top-level const anyway. There is no distinction between a const and non-const prvalue of a non-class type. So the type of foo() is just int, no matter whether it is declared to return const int or int.
It would be different if the return type was a const qualified class type, e.g. const std::string foo(). In that case the const would disallow calling non-const-qualified member functions directly on the result of foo(), e.g. foo().resize(42). Still, this is a very rarely used distinction. And as noted in the comments, under certain conditions it can prevent move operations. E.g. in the above if we have a std::vector<std::string> v;, then v.push_back(foo()) will cause a copy, rather than a move, of the returned string into the vector.
However, the const qualifier is part of the return type in the function type and therefore it is technically possible to differentiate a function declared with const return type from one without it. The type of int foo(int foo) is int(int), but the type of const int foo(int foo) is const int(int). (However overloading based on return type is not possible for non-template functions anyway. The return type is not part of the function signature.)
correct
Same as 1. The type of foo() is simply int*.
The top-level const in the function parameter does not affect the type or signature of the function (in contrast to 1. where it does affect the type). So int foo(const int foo); and int foo(int foo); declare the same function and both have type int(int). Top-level const also doesn't affect how a variable can be initialized, so it doesn't make sense to say "you can only pass in const int". There are no const-qualified prvalues of type int anyway and if int foo can be initialized from some expression, then so can const int foo. The const has no implication on initialization or overload resolution. However const can be used like this in a function definition to tell the compiler and yourself that this parameter is not intended to be modified in the definition.
Same as 4.
This is the correct idea, although in the details it is not strictly true. Rather the const is only relevant to overload resolution (behaving as if the implicit object parameter was a const reference) and the type of this (which will be a pointer to const). It is still possible to mutate members declared as mutable or to use const_cast to mutate members. It is also not relevant whether the object itself is const, only whether the glvalue through which the member function is called is.

Is the `const` keyword used in function declaration, or definition or both?

void test(int& in);
void test(const int& in){
}
int main(){
int a = 5;
test(a);
return 0;
}
Above doesn't compile with a link error: undefined reference to `test(int&)'.
I have 3 questions on this:
1- Why do we get a link error? is it because adding const to the definition makes it a completely different function? why would it work when not using references, i.e this works fine:
void test(int in);
void test(const int in){}
..
int a = 5;
test(a);
..
2- Does const go in function declaration, or definition or both? Seems like
the behaviour is different if references are used.
3- Does the const keyword on an argument say "the parameter passed to me should be a constant in the caller" or "this parameter is treated as a constant in this function scope, regardless of it being constant in the caller or not". I'm sure it's the latter but wanted to confirm.
In C++ the two functions:
void test(int& in);
void test(const int& in);
are TWO different, overloaded functions. The first binds to "writeable" integers, the second - to constant ones.
In your code:
int a = 5;
test(a);
a is a modifiable object, hence void test (int &) is a better match from compiler perspective and it selects this function for a call.
The reason why you are getting linker error is that you declared but not defined this function.
In both cases below the const function would have been selected:
int const a = 5;
test(a);
test(10);
Additionally if you only had const version declared as below, it would have been selected as well:
//void test(int &in);
void test(const int &in){}
..
int a = 5;
test(a);
..
As for the second question in case of references - const goes both to declaration and definition as these are different functions.
With normal values there is NO difference between the two when declared:
void test(int in);
void test(const int in);
They refer to THE SAME function. The const version will prevent modification of the function parameter in function definition.
For the third one, when applied to references it means two things:
A reference will be passed to a function and not a copy for an object.
When accompanied by a const it promises to the caller not to modify referenced object and prevents the function from doing so.
A function-definition is always also a function-declaration.
Thus, to differentiate them, the latter is often called a forward-declaration if it is not also a definition.
The function-signature used for overload-resolution derives from the function-declaration, and there are a few peculiarities in deriving it from the written source:
Top-level cv-specifiers on argument-types are discarded.
Top-level cv-specifiers on return-type are discarded if the type is not a class- or union-type. (A struct is a class-type.)
The function is not affected by these rules outside overload-resolution and matching declarations.
Applied to your examples:
void test(int& in);
void test(const int& in) { // const is not top-level
// The above two declarations are for different functions
void test(int in);
void test(const int in){} // const is top-level
// Equivalent declarations above
A function definition is also a function declaration. Thus, you declare two overloaded functions, but only one function is defined, has a body.
The compiler choses the first function, since a is not const and the first choice is the exact match.
You get the linker error, since the first function has no definition, i.e. no body.
It's best to do both, as the const keyword is intended to hint at the user that the variable will not be modified. I believe most compilers will treat a const type as a different type as well, so you'll have a compile error.

const keyword position in function declaration [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Difference between const declarations in C++
#include <iostream>
class Bar{};
void foo(const Bar x){} //l5
void foo(Bar x){} //l6
void foo(Bar const x){} //l7
////pointer functions
void foo(const Bar* x){} //l11
void foo(Bar* x){} //l12
void foo(Bar* const x){} //l13
Compiler output: (long story short l5,l6,l7 conflict; but only l12,l13 conflict)
untitled.cpp:6:6: error: redefinition of ‘void foo(Bar)’
untitled.cpp:5:6: error: ‘void foo(Bar)’ previously defined here
untitled.cpp:7:6: error: redefinition of ‘void foo(Bar)’
untitled.cpp:5:6: error: ‘void foo(Bar)’ previously defined here
untitled.cpp:13:6: error: redefinition of ‘void foo(Bar*)’
untitled.cpp:12:6: error: ‘void foo(Bar*)’ previously defined here
What going on?
What is the meaning of each of the declarations
Why does all 3 declarations conflict with object functions but only 2 with pointer functions?
Please elaborate that conflict is between l12 and l13, even though l12 does not contain const keyword
Really sorry if trivial question
The "problem" is that constness of a parameter's value doesn't participate in overloading!
First, Bar const and const Bar are already identical meaning, so they would automatically have a problem. But as a function parameter the const doesn't apply to overloading so the Bar version of the function also looks the same too. The const in the paremeter only tells the compiler that you don't intend to modify it in the function body.
For the same reason, Bar* and Bar* const are treated the same: The const applies to the value of the parameter (not what's pointed to) and does not participate in overloading, so you've defined the same function.
On the other hand const Bar* means something totally different: A non-const pointer to a const object (of type Bar). Since the type is different it does participate in overloading and allows that function to be unique.
Basically, because C++ copies values when calling a function, there is nothing to distinguish the first three from a callers perspective. (The caller knows the function can't change it's own value it's passing in, so every function parameter is implicitly constant in a lot of regards, from the perspective of the caller at any rate).
When you talk about pointers however, if you pass a pointer to a constant vs a pointer to a non constant, there is a difference to the caller (one wont change your stuff, the other might). This is why l11 and l12 don't conflict.
l12 and l13 conflict though because they are both pointers to Bar* (one is a const pointer, one is not, so same problem as l5-l7, there's no difference to the caller).
This last point may be a little tricky - note that while int const *a is the same as const int *a, these are not the same as int * const a, the first two are pointers to a constant int, the other is a constant pointer to an int (ie the value of the pointer can't change in the later).
It doesn't matter whether you put const before or after the type name.
15 and 17 have the same parameter argument list.
These 2 functions are considered to have the same prototype and are duplicates.
Function #1
void foo(const int x) {
return;
}
Function #2 - Duplicate parameter argument list
void foo( int const x) {
return;
}
The position of const is the same as 15 and 17 in the example you have.
Either will work according to Wikipedia:
http://en.wikipedia.org/wiki/Const-correctness
void foo(const Bar x){}
void foo(Bar const x){}
The above two are identical because both say x is of Bar type and it is const.
void foo(Bar x){}
This one conflicts with the above 2 because whether x is const or not is an implementation detail of your function, and is discarded by the compiler from the function signature. So all 3 functions end up having the same signature which is void foo( Bar x ).
void foo(Bar* x){}
void foo(Bar* const x){}
This is similar to the previous case; you're indicating that the pointer x is const i.e. you will not re-point x to something thing else within your function. In both cases the Bar object that x points to is non-const. Thus the constness of x is an implementation detail of the function.
void foo(const Bar* x){}
Here you're indicating that x points to a Bar object which is const. This is different from the previous 2 cases, and so there is no conflict.
The reason the first three create a conflict, is that the compiler can't figure out which function to use in any case. When you call foo(BarObject); the compiler could very well use any of them whether was declared BarObject as const or not.
However on the ones with parameters as pointers, when you call foo(BarPointer); if BarPointer was declared as const Bar* BarPointer; the compiler will pick ]11, because it ensures the object pointed to will not be modified in the function (not the case when passing by value as in the first three). If it isn't const, it doesn't know if it should call ]12 or ]13 because what Bar* const x means is, "x can't point to anything else than what was passed as a parameter" and this doesn't concern the caller.
Small reference to the declarations:
const Bar x // x is an immutable copy of the original parameter.
Bar const x // same as above and gets compiled, but cdecl says it is a syntax error.
const Bar* x // x points to an object that can't be changed.
Bar* const x // x can't point to any other object than the parameter passed.
For the first three function - const doesn't matters on overloading resolution in case variable transferred by value. Copy of argument created on the stack and it doesn't make sense if this copy changed or not from the outside(caller) point of view. It matters for function itself (inside).
For second case, pointer based functions, it's important part of function overload resolution, because copies are not created on the stack and from the outside(caller) point of view it means function will or not modify argument's value.
For last two functions use say to a compiler: there is x pointer to Bar, and this Bar value pointed by x I may change. But in first case you can change value of pointer x itself (say, point to another Bar) opposite to the second case. And here we are in the first situation - copies of pointers themselves are on the stack and it doesn't make sense for overloading resolution if they changed inside of the function or not.

C++ overloading with one parameter const

Why is following not allowed in C++
#include <iostream>
class Sample {
public:
void Method(char x);
void Method(char const x);
};
void Sample::Method(char x) {
char y = x;
}
void Sample::Method(char const x) {
char y = x;
}
int main() {
Sample s;
return 0;
}
Why is following not allowed in C++?
The reason is the very same that the compiler gives you as an compilation error:
Because they are ambiguous!
Why are these methods ambiguous?
Short answer: Because the C++ Standard says so.
What is the rationale behind these overloaded methods being ambiguous?
The compiler does not know whether the caller wants to treat the value of the passed argument as an const or not, there is no way for the compiler to determine that with the information at hand.
Note the emphasis on pass by value here, the argument is being passed by value, and hence the ambiguity. If the argument was passed by reference then the compiler knows for sure how the caller wants to treat the argument because then the actual object itself is being passed, and hence compiler can make a selection of the proper overload.
The following example gives a clearer idea to the explanation above.
Online Sample:
class Sample
{
public:
void Method(char &x){}
void Method(char const x){}
void Method(char const &x){}
};
int main()
{
Sample s;
return 0;
}
It doesn't really answer why, but it is determined by the standard, §1.3.10
The information about a function that participates in overload resolution (13.3): the types of its parameters
and, if the function is a class member, the cv- qualifiers (if any) on the function itself and the class in which the member function is declared.
This just means the cv qualifiers of the arguments are ignored in the overload resolution.
A similar (but not equivalent) example with references works:
class Sample {
public:
void Method(char& x) {}
void Method(const char& x) {}
};
because here the types are different, the first case being a reference to char, the second a reference to const char (as opposed to a const reference to char).
When it comes to function parameters, char and char const are the same data type.
This is still ambiguous. When it's called with a character argument, one version will copy the argument and say "OK, you can change the copy". The other will copy the argument and say "OK, you cannot change the copy." How is the compiler supposed to know whether it can or can't change a copy of something? It could do either just fine.
because it's ambiguous
when you're passing like this
s.Method('x');
what version should you think be called?
The standard says those two declarations are equivalent (13.1.3):
Parameter declarations that differ only in the presence or absence of const and/or volatile are equivalent. That is, the const and volatile type-specifiers for each parameter type are ignored when determining which function is being declared, defined, or called.
typedef const int cInt;
int f(int);
int f(const int); // redeclaration of f(int)
int f(int) { /* ... */ } // definiton of f(int)
int f(cInt) { /* ... */ } // error: redefiniton of f(int)
http://duramecho.com/ComputerInformation/WhyHowCppConst.html
Because const denotes that variable as having a set value, that cannot be changed after declaration. It is not a different data type.

ambigious functions in c++

I would like to know why these declarations won't work(are not compatible)
void f(int); //p1
void f(const int);//p2
void f(int &);//p3
void f(const int &);//p4
If I understood well, the compiler won't find a difference between (int &) and (const int &)
and if I write f(12) it won't be able to choose between the two first declarations..
Am I right?
p3 and p4 are perfectly unambiguous and distinguishable, p1 and p2 are not. (And of course p1/p2 are distinguishable from p3 and p4.)
The reason is that top-level const on a value parameter is not detectable and infact useless on a declaration. You can for example do the following:
void foo(int x); // declaration
// ...
void foo(const int x){
// definition/implementation
}
The const here is an implementation detail that's not important for the caller, since you make a copy anyways. That copy is also the reason why it's not distinguishable from just int, from the callers side it's exactly the same.
Note that const int& r does not have a top-level const, it's the reference that refers to a constant integer (references are always constant). For pointers, which may be changed if not declared const, see also this question for where to put const.