Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you use stl's functions like for_each?

Tags:

c++

function

stl

I started using stl containers because they came in very handy when I needed the functionality of a list, set and map and had nothing else available in my programming environment. I did not care much about the ideas behind it. STL documentation was interesting up to the point where it came to functions, etc. Then I skipped reading and just used the containers.

But yesterday, still being relaxed from my holidays, I just gave it a try and wanted to go a bit more the stl way. So I used the transform function (can I have a little bit of applause for me, thank you).

From an academic point of view it really looked interesting and it worked. But the thing that bothers me is that if you intensify the use of those functions, you need thousands of helper classes for mostly everything you want to do in your code. The whole logic of the program is sliced into tiny pieces. This slicing is not the result of good coding habits; it's just a technical need. Something, that makes my life probably harder not easier.

I learned the hard way, that you should always choose the simplest approach that solves the problem at hand. I can't see what, for example, the for_each function is doing for me that justifies the use of a helper class over several simple lines of code that sit inside a normal loop so that everybody can see what is going on.

I would like to know, what you are thinking about my concerns? Did you see it like I do when you started working this way and have changed your mind when you got used to it? Are there benefits that I overlooked? Or do you just ignore this stuff as I did (and will go on doing it, probably).

Thanks.

PS: I know that there is a real for_each loop in boost. But I ignore it here since it is just a convenient way for my usual loops with iterators I guess.

like image 352
user331471 Avatar asked May 18 '10 11:05

user331471


2 Answers

The whole logic of the program is sliced in tiny pieces. This slicing is not the result of good coding habits. It's just a technical need. Something, that makes my life probably harder not easier.

You're right, to a certain extent. That's why the upcoming revision to the C++ standard will add lambda expressions, allowing you to do something like this:

std::for_each(vec.begin(), vec.end(), [&](int& val){val++;})

but I also think it is often a good coding habit to split up your code as currently required. You're effectively separating the code describing the operation you want to do, from the act of applying it to a sequence of values. It is some extra boilerplate code, and sometimes it's just annoying, but I think it also often leads to good, clean, code.

Doing the above today would look like this:

int incr(int& val) { return val+1}

// and at the call-site
std::for_each(vec.begin(), vec.end(), incr);

Instead of bloating up the call site with a complete loop, we have a single line describing:

  • which operation is performed (if it is named appropriately)
  • which elements are affected

so it's shorter, and conveys the same information as the loop, but more concisely. I think those are good things. The drawback is that we have to define the incr function elsewhere. And sometimes that's just not worth the effort, which is why lambdas are being added to the language.

like image 101
jalf Avatar answered Oct 27 '22 01:10

jalf


I find it most useful when used along with boost::bind and boost::lambda so that I don't have to write my own functor. This is just a tiny example:

class A
{
public:
    A() : m_n(0)
    {
    }

    void set(int n)
    {
        m_n = n;
    }

private:
    int m_n;
};

int main(){    

    using namespace boost::lambda;

    std::vector<A> a;
    a.push_back(A());
    a.push_back(A());

    std::for_each(a.begin(), a.end(), bind(&A::set, _1, 5));


    return 0;
}
like image 24
Naveen Avatar answered Oct 27 '22 00:10

Naveen