'Use of a functor on for_each

Why does the for_each call on functor doesn't update sum::total at the end?

struct sum
{
    sum():total(0){};
    int total;

    void operator()(int element) 
    { 
       total+=element; 
    }
};

int main()
{
    sum s;

    int arr[] = {0, 1, 2, 3, 4, 5};
    std::for_each(arr, arr+6, s);
    cout << s.total << endl; // prints total = 0;
}


Solution 1:[1]

for_each takes the functor by value - so it is copied. You can e.g. use a functor which is initialized with a pointer to an external int.

struct sum
{
    sum(int * t):total(t){};
    int * total;

    void operator()(int element)
    {
       *total+=element;
    }
};

int main()
{
    int total = 0;
    sum s(&total);

    int arr[] = {0, 1, 2, 3, 4, 5};
    std::for_each(arr, arr+6, s);
    cout << total << endl; // prints total = 15;
}

Or you can use the return value from for_each

struct sum
{
    sum():total(0){};
    int total;

    void operator()(int element) 
    { 
       total+=element; 
    }
};

int main()
{
    sum s;

    int arr[] = {0, 1, 2, 3, 4, 5};
    s = std::for_each(arr, arr+6, s);
    cout << s.total << endl; // prints total = 15;
}

Solution 2:[2]

for_each receives a copy of your functor by value. Even after that, it's free to copy it, but does return a copy.

OTOH, you're simply trying to re-invent std::accumulate, which will do the job much more easily:

int total = std::accumulate(arr, arr+6, 0);
cout << total << endl; 

Solution 3:[3]

Because the s which you pass to the for_each is by value. for_each accepts it by value!

In C++0x, you can solve this problem with for_each as,

int sum  = 0;
std::for_each(arr, arr+6, [&](int n){ sum += n; });
std::cout << sum ;

Output:

15

Demo at ideone : http://ideone.com/s7OOn


Or you can simple write in the std::cout itself:

std::cout<<std::for_each(arr,arr+6,[&](int n)->int{sum += n;return sum;})(0);

Run : http://ideone.com/7Hyla

Note such different syntax is okay for learning purpose, as to how std::for_each works, and what it returns, but I would not recommend this syntax in real code. :-)


In C++, you can write user-defined conversion function in the functor as,

struct add
{
    int total;
    add():total(0){};
    void operator()(int element)  {  total+=element;  }
    operator int() { return total ; }
};

int main()
{
    int arr[] = {0, 1, 2, 3, 4, 5};
    int sum = std::for_each(arr, arr+6, add());
    std::cout << sum;
}

It's slightly different version from Erik second solution : http://ideone.com/vKnmA

Solution 4:[4]

This happens due to std::for_each requires the functor to be passed by value . A workaround for your solution:

struct sum
{
    sum():total(0){};
    int total;
    sum(sum & temp)
    {
        total = temp.total;
    }
    void operator()(int element) 
    { 
       total+=element; 
    }
};

int main()
{
    sum s;

    int arr[] = {0, 1, 2, 3, 4, 5};
    s = std::for_each(arr, arr+6, s);  // result of for_each assigned back to s
    cout << s.total << endl; // prints total = 0;
}

Solution 5:[5]

std::ref() is also another option if you want your object state gets updated after std::for_each

struct Sum
{
    int total = 0;
    void operator()(int i) { total += i; }
};

int main()
{
    int arr[] = { 0, 1, 2, 3, 4, 5 };

    Sum obj1;
    Sum t1 = std::for_each(arr, arr + 6, obj1);  // t1.total = 15 
                            // (Note: obj1.total = 0 bcos it is passed by value)

    Sum obj2;
    std::for_each(arr, arr + 6, std::ref(obj2)); // obj2.total = 15 (NO copy)

    Sum t2 = std::for_each(arr, arr + 6, Sum()); // t2.total = 15
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Erik
Solution 2 Jerry Coffin
Solution 3
Solution 4 rahul
Solution 5 SridharKritha