Reputation: 485
I was trying to test some simple C-style sort functions. In the driver program, I wrote something like this:
int main()
{
std::array<int, 8> A = { 1, 0, 4, 5, 7, 2, 9, 3 };
auto lambda = [&A](const std::function<void(int *A, int n)> &sorting_alg) {
int n = A.size();
sorting_alg(A.data(), n);
std::cout << "=> ";
print(A.data(), n);
std::cout << std::endl;
};
auto do_bubble_sort = std::bind(lambda, bubble_sort);
auto do_selection_sort = std::bind(lambda, selection_sort);
auto do_insertion_sort = std::bind(lambda, insertion_sort);
std::cout << "Bubble Sort :" << std::endl;
do_bubble_sort();
std::cout << "Selection Sort :" << std::endl;
do_selection_sort();
std::cout << "Insertion Sort :" << std::endl;
do_insertion_sort();
return 0;
}
I had the bind code, to which I could pass A
to copy, but it confines my lambda to size=8
, which I want to avoid. Is it possible to achieve this without using something like std::vector
, etc?
As soon I change capture method of A
to value-capture, it doesn't compile anymore. I wanted to use copies for the array, to test all sorting functions. Why can't I capture std::array
by value? Why then size-inference works for reference case?
Upvotes: 3
Views: 964
Reputation: 10624
The problem is that the operator()
of the lambda function is const
-qualified by default. This means that the values captured by value are const
-qualified in the lambda body. In your code, you are trying to invoke std::function
with a non-const
pointer to int
initialized from the captured array, which is const
.
To fix this you need to mark your lambda as mutable
so that the generated operator()
is no longer const
-qualified:
auto lambda = [A](const std::function<void(int *A, int n)> &sorting_alg) mutable {
...
}
Upvotes: 1
Reputation: 41800
You can capture by value, but you have to change the lambda to a mutable one.
When you capture by value, the captures are const by default. You can mark it mutable or make a copy locally:
auto lambda = [A](const std::function<void(int *A, int n)> &sorting_alg) {
auto ALocal = A;
int n = ALocal.size();
sorting_alg(ALocal.data(), n);
std::cout << "=> ";
print(ALocal.data(), n);
std::cout << std::endl;
};
This has the advantage of making the lambda callable multiple times.
You can do this with capture by reference too.
You can alternatively make the lambda mutable, but callable only once:
auto lambda = [A](const std::function<void(int *A, int n)> &sorting_alg) mutable {
int n = A.size();
sorting_alg(A.data(), n);
std::cout << "=> ";
print(A.data(), n);
std::cout << std::endl;
};
Upvotes: 3
Reputation: 180955
The operator()
of a lambda is const
by default. That means you can't modify any members of the lambda (it's captures). When you capture by reference, this means you can't change the reference to refer to something else, but since you can't do that already it basically means nothing. When you capture by value it makes that value const
, which means you can no longer modify like your sorting method requires (you need data
to return a non-const pointer).
To get around this you can use the mutable
keyword to make the lambda's operator()
not const
. That would look like
auto lambda = [A](const std::function<void(int *A, int n)> &sorting_alg) mutable {
int n = A.size();
sorting_alg(A.data(), n);
std::cout << "=> ";
print(A.data(), n);
std::cout << std::endl;
};
Upvotes: 7