4

This is a newbie C++ question. I was reading the "Function object" article in Wikipedia. The article has an example in C++ similar to the following:

struct printClass {
  int &count;

  printClass(int &n) : count(n) {}

  void operator()(int &i) const {
      count++;
      cout << i << "[" << count << "] ";
  }
};

int main(int argc, char** argv) {
    vector<int> a(5, 7);
    a[4] = -1;
    a.resize(10, 3);
    int state = 0;
    for_each(a.rbegin(), a.rend(), printClass(state));
}

I have 2 questions:

  1. Why does it fail to compile when count is a regular variable not a reference type? Demo

  2. Why does it fail to compile it I change the ctor to the following? Demo

    printClass(int &n) { count = n; }

Thanks.

EDIT: Thanks for explaining. I see that the following version works, too. Is there a reason for chosing one over another?

struct printClass {
  int count;

  printClass(int n) { count  = n; }

  void operator()(int &i) {
      count++;
      cout << i << "[" << count << "] ";
  }
};

EDIT: Based on iammilind's reply, here is the 3rd version that works too using const_cast<int &>.

struct printClass {
  int count ;

  printClass(int n) : count(n) {}

  void operator()(int &i) const {
      const_cast<int &>(count)++;
      cout << i << "[" << count << "] ";
  }
};
codefx
  • 9,872
  • 16
  • 53
  • 81
  • 3
    Please show us the exact code you're trying to compile, and the exact error message(s) you're getting. – NPE Mar 17 '13 at 06:53
  • I have updated the question with the exact example I am trying. PTAL – codefx Mar 17 '13 at 07:08

1 Answers1

4

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

David G
  • 94,763
  • 41
  • 167
  • 253
iammilind
  • 68,093
  • 33
  • 169
  • 336