Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a variable become 'const' when I use a [=] capture (using Lambda class)?

Premise #1: I have already solved the error, but I didn't deeply understand the cause of the compiler error.

Premise #2: The goal of this program is to copy a image into another image by a multithreaded process. Maybe a better way exists, but this is not the focus topic of the question (see premise #1).

I wrote a simple program using OpenCV 3.1 library to copy a image into another image. It takes advantage of all cores of the CPU using more threads.

The code is:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <thread>

using namespace cv;
using namespace std;

#define IMG_PATH "..\\img\\50a.png"


void copy_image(const Mat& input, Mat& output, int row_offset, int skip_row)
{
    cout << row_offset;
    Size size = input.size();
    for (int r = row_offset; r < size.height; r += skip_row)
    {
        for (int c = 0; c < size.width; c++)
        {
            output.at<Vec3b>(r, c) = input.at<Vec3b>(r, c);
        }
    }
}

int main()
{
    Mat input_img = imread(IMG_PATH);
    Mat output_img = Mat(input_img.size(), input_img.type()); output_img.setTo(255);

    vector<thread> threads;
    int thread_number = thread::hardware_concurrency();

    for (int i = 0; i < thread_number; i++)
    {
        cout << i;
        auto var = [=]() 
        {
            return copy_image(input_img, output_img, i, thread_number);
        };

        threads.push_back(thread(var));
    }

    for (auto& thread : threads) 
        thread.join();

    imshow("output_img", output_img);
    imwrite("result.png", output_img);
    waitKey(0);
}

The compiler returns me this error

Error C2664 'void copy_image(const cv::Mat &,cv::Mat &,int,int)': cannot convert argument 2 from 'const cv::Mat' to 'cv::Mat &'

that it reffers this line of code:

return copy_image(input_img, output_img, i, thread_number);

I solved this error replacing this line

auto var = [=]()

with this

auto var = [=, &input_img, &output_img]() 

but actually I don't deeply understand why I received that error.

like image 383
Radioga Avatar asked Aug 21 '16 13:08

Radioga


People also ask

Why is lambda capture Const?

By default, variables are captured by const value . This means when the lambda is created, the lambda captures a constant copy of the outer scope variable, which means that the lambda is not allowed to modify them. In the following example, we capture the variable ammo and try to decrement it.

How do you capture a variable in lambda function?

Capturing Local Variables by value inside Lambda Function To capture the local variables by value, specify their name in capture list i.e. }; // Local Variables std::string msg = "Hello"; int counter = 10; // Defining Lambda function and // Capturing Local variables by Value auto func = [msg, counter] () { //... };

Can a lambda be const?

constexpr lambda expressions in C++ Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): A lambda expression may be declared as constexpr or used in a constant expression when the initialization of each data member that it captures or introduces is allowed within a constant expression.

What does it mean to lambda capture this?

A lambda is a syntax for creating a class. Capturing a variable means that variable is passed to the constructor for that class. A lambda can specify whether it's passed by reference or by value.


2 Answers

If you do a capture by value in a lambda, you will get a 'member' which gets stored. As the default operator() is a const function, you cannot modify them.

Lambdas can be defined as []() mutable {} to allow you to modify the local variables.

By capturing the value by reference, you have something which behaves like a const pointer to a non-const object, so without the mutable, you can adapt those objects. (Unless they already where const)

like image 139
JVApen Avatar answered Oct 04 '22 13:10

JVApen


Captured variables are indeed const in the scope of the lamba:

[foo]()
{
   // foo, whatever that is, is const
}

In a mutable lambda, the captured variables are not constant:

[foo]()
mutable {

   // Lambda can modify foo, but it's a copy of the original
   // captured variable
}
like image 39
Sam Varshavchik Avatar answered Oct 04 '22 14:10

Sam Varshavchik