tags:

views:

150

answers:

1

I'm trying to initialize a list to random integers using a for_each and a lambda function. I'm new to boost.lambda functions so I may be using this incorrectly but the following code is producing a list of the same numbers. Every time I run it the number is different but everything in the list is the same:

srand(time(0));

theList.resize(MaxListSize);

for_each(theList.begin(), theList.end(), _1 = (rand() % MaxSize));
+6  A: 

Boost lambda will evaluate rand before the functor is made. You need to bind it, so it's evaluated at lambda evaluation time:

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp> // for bind
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>

int main(void)
{
    namespace bl = boost::lambda;
    typedef std::vector<int> int_vec;

    static const size_t MaxListSize = 10;
    static const int MaxSize = 20;

    int_vec theList;
    theList.resize(MaxListSize);

    std::srand(static_cast<unsigned>(std::time(0)));
    std::for_each(theList.begin(), theList.end(),
                    bl::_1 = bl::bind(std::rand) % MaxSize);

    std::for_each(theList.begin(), theList.end(), std::cout << bl::_1 << ' ' );
}

This works as expected. Note that for_each is suppose to be non-mutating. In your specific usage, you would want transform (to "transform" the range from "0,0,0,..." to your values):

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>

int main(void)
{
    namespace bl = boost::lambda;
    typedef std::vector<int> int_vec;

    static const size_t MaxListSize = 10;
    static const int MaxSize = 20;

    int_vec theList;
    theList.resize(MaxListSize);

    std::srand(static_cast<unsigned>(std::time(0)));
    std::transform(theList.begin(), theList.end(), theList.begin(),
                    bl::_1 = bl::bind(std::rand) % MaxSize);

    std::for_each(theList.begin(), theList.end(), std::cout << bl::_1 << ' ' );
}

However, the correct solution is to use generate_n. Why make a bunch of 0's just to overwrite them?

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>

int main(void)
{
    namespace bl = boost::lambda;
    typedef std::vector<int> int_vec;

    static const size_t MaxListSize = 10;
    static const int MaxSize = 20;

    int_vec theList;
    theList.reserve(MaxListSize); // note, reserve

    std::srand(static_cast<unsigned>(std::time(0)));
    std::generate_n(std::back_inserter(theList), MaxListSize,
                    bl::bind(std::rand) % MaxSize);

    std::for_each(theList.begin(), theList.end(), std::cout << bl::_1 << ' ' );
}
GMan
Thank you, Roger. :)
GMan
Ahh, nice one that's a great response.
Demps