How to capture variable inside lambda
As mch said in the comment, the problem is that k
is not a compile time constant.
For a compile time constant, to iterate from N
to 0
, you may need template and recursion:
#include <algorithm>
#include <tuple>
#include <type_traits>
#include <vector>
using namespace std; // just for simplify, and not recommended in practice
template <size_t N, typename Iterator, enable_if_t<N == 0, int> = 0>
void foo(Iterator begin, Iterator end)
{
sort(begin, end,
[](const auto &t1, const auto &t2) {
return get<0>(t1) < get<0>(t2);
}
);
}
template <size_t N, typename Iterator, enable_if_t<N != 0, int> = 0>
void foo(Iterator begin, Iterator end)
{
sort(begin, end,
[](const auto &t1, const auto &t2) {
return get<N>(t1) < get<N>(t2);
}
);
foo<N - 1>(begin, end);
}
int main()
{
vector<tuple<int, int>> v{{0, 1}, {0, 0}, {1, 1}};
foo<1>(v.begin(), v.end());
// posible results:
// {0, 0}, {0, 1}, {1, 1}
// {0, 1}, {0, 0}, {1, 1} // impossible if use std::stable_sort instead
}
std::get
only accepts a template argument which is an expression whose value that can be evaluated at compiling time.
You can't use k
, because it is a variable that changes value.
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
const int k = 3;
return std::get<k>(t1) < std::get<k>(t2); // or use a custom compare function
});
As I wrote in the comments, I know const int = 3
will shadow the k
value outside of the lambda expression, but this example shows that get
will work when it it receives a compiling time constant value.
For example, if you try to set k = 5
, for example where v
only has 4 tuple parameters, the compiler will give an error because it knows that this is out of range.
The following code will give an error, but if k
is set to 3, it will work
std::vector<std::tuple<int, int, int, int>> v;
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
const int k = 5;
return std::get<k>(t1) < std::get<k>(t2); // or use a custom compare function
});