Ari Seyhun
Ari Seyhun

Reputation: 12541

"Capture" variables in lambda function parsed as argument

I have no idea what to title this question as, sorry.


I have a function in C++ which takes a lambda as a parameter.

void LoopPixels(cv::Mat &img, void(*fptr)(uchar &r, uchar &g, uchar &b)) {
    // ...
    fptr(r, g, b); // Call the lambda function
}

Then I am trying to call this LoopPixels function.

int threshold = 50;
LoopPixels(img, [](uchar &r, uchar &g, uchar &b) {
    r *= (uchar)threshold; // Unable to access threshold :(
});

My problem is, I cannot access the threshold variable from inside the lambda function, and if I try to "catch" it with [&threshold](uchar &r...){}, I receive an error telling me the lambda I parsed into LoopPixels is of the wrong type.

Error message:

no suitable conversion function from "lambda []void (uchar &r, uchar &g, uchar &b)->void" to "void (*)(uchar &r, uchar &g, uchar &b)" exists

How can I access variables within a lambda which has been parsed as a function argument?

Upvotes: 2

Views: 416

Answers (2)

gabdib
gabdib

Reputation: 11

You can try to use this:

void LoopPixels(cv::Mat& img, uint& r, uint& g, uint& b, const std::function<void(uint& r, uint& g, uint& b)>& callback)
{
    callback(r, g, b);
}

cv::Mat img;
int threshold = 50;
uint r = 1;
uint g = 1;
uint b = 1;

std::cout << "(before) rgb : " << r << g << b << std::endl;

LoopPixels(img, r, g, b, [threshold](uint& r, uint& g, uint& b)
{
   r *= threshold;
   g *= threshold;
   b *= threshold;
});

std::cout << "(after) rgb : " << r << g << b << std::endl;

The lamba capture is passed by value because the reference could go out of scope before the callback call.

(I used uint for r, g, b variables instead of uchar because multiplying a uchar for an int might not give the result you expect).

Upvotes: 0

hansmaad
hansmaad

Reputation: 18915

You cannot pass a capturing lambda to a function pointer. You have to change the function to use a std::function, or use a function template.

void LoopPixels1(cv::Mat &img, std::function<void(uchar &r, uchar &g, uchar &b)> fn);
// Or:
template<typename Callable>
void LoopPixels2(cv::Mat &img, Callable fn);

// Can be called with a capturing lambda
LoopPixels1(img, [threshold](uchar &r, uchar &g, uchar &b) { });
LoopPixels2(img, [threshold](uchar &r, uchar &g, uchar &b) { });

Upvotes: 5

Related Questions