Adam27X
Adam27X

Reputation: 883

C++11: Cannot capture `this` when trying to capture member of class in lambda function

I'm writing a simple test to see how C++11 Lambdas can be used for the purpose of maximizing code reuse. I have a function, fill_vector() and in one case I'd like it to simply fill a vector with random numbers, but in another case I'd like it to also provide me with the maximum of those numbers.

Here's what I have so far:

#include <iostream>
#include <random>
#include <vector>
#include <algorithm>
#include <iterator>

template <class Function>
void fill_vector(std::vector<int> &v, Function side)
{
    for(auto i=v.begin(); i!=v.end(); ++i)
    {
            *i = rand() % 100;
    }
    side.lambda(v);
}

class null_test
{
public:
    constexpr static auto lambda = [] (std::vector<int> x) { };
};

class test
{
public:
    test() : max(0) { } 

    int max;
    static auto lambda = [=] (std::vector<int> x) { max = 
        std::max_element(x.begin(),x.end()); };
};

int main()
{
    std::vector<int> v(20);
    null_test n;
    fill_vector(v,n);

    std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout," "));

    std::cout << std::endl;

    std::vector<int> v2(20);
    test t;
    fill_vector(v2,t);
    std::copy(v.begin(),v.end(),std::ostream_iterator<int>(std::cout," "));
    std::cout << std::endl;
    std::cout << t.max << std::endl;

    return 0;
}

Which results in the error: ‘this’ was not captured for this lambda function, pointing at my lambda defined in test. I've tried all sorts of capture statements and can't seem to get anything to work. What am I missing?

Also, is it possible to use a lambda inside the loop of fill_vector that could, say, extract every nth element filled? My goal here is to be able to reuse a function like fill_vector as much as possible for other functions that might need slight variations of it in a bigger project.

Upvotes: 0

Views: 1090

Answers (1)

Barry
Barry

Reputation: 303057

Looking at your class test:

class test
{
public:
    int max;
    static auto lambda = [=] (std::vector<int> x) {
        max = std::max_element(x.begin(),x.end()); 
    };
};

There are several problems here:

  1. operator() on a lambda is const, and you are trying to modify a member.
  2. You are trying to assign the value to an external variable, but are capturing it by-value, so even if you made the lambda mutable, nothing would happen.
  3. You are trying to assign a member of a class using a static function that does not take an instance of that class.
  4. As dyp points out, std::max_element returns an iterator, not the actual element.

The lambda you want to write probably looks like this:

test t;
std::vector<int> v2(20);
fill_vector(v2, [&t](const std::vector<int>& x){
    t.max = *std::max_element(x.begin(), x.end());
});

Just change your fill_vector() function to take a callable, rather than something that has a callable.

Upvotes: 3

Related Questions