(1) Why does it fail to compile when count is a regular variable not a
reference type?
This is a very interesting question. The question should be rather, why the code compiles when count
is declared as a reference. :)
The regular variable fails because int count
is not modifiable inside a const
qualified function operator()(int &i) const;
.
References are little different. In your code you are declaring the method as const
, which means that count
which is referring to i
, now cannot refer to anything else.
But that's anyway not possible due to nature of references :). One cannot change reference binding after the initialization.
operator()
just checks whether you are changing the binding of count
to anything else or not? And the answer is always no. Because count++
changes the value referred by count
and not the binding.
In your code, it doesn't matter if a member method is const
or not when it comes to int& count
.
Relate int& count;
to int* const p_count;
and try to simulate the situation on your own.
(2) Why does it fail to compile it I change the ctor to the following?
CountFrom(int &n) { count = n; }
Because reference must be assigned to a variable while initialization. In simple example;
int i, &r; // error, because 'r' not initialized
r = i; // this is not initialization but a copy
On a side note, you should be extra careful when you are dealing with reference variables inside a class
. Because it's easy to mess up with their scope and validity.
For example, here the validity of count
is dependent on the scope of i
.
Edit: After your 2nd edit, it's very trivial to know why that version works.
Because count
is now a simple variable. It can be skipped from initialization in the initializer list of the constructor unlike reference.
Moreover the const
correctness of the operator()
is gone, so any member variable of the class
can now be modified inside it.
You should choose a const
version of the member method, if you want to state that no class
member "must" change inside it (unless any variable is mutable
or you use const_cast
). In all other cases use the normal version of the member method. They both can co-exist as well depending on your business logic. This is a bit of a broad question and it's worth to have another thread for this.