[英]How to capture variable inside lambda
I have code from here :我有来自这里的代码:
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
return get<0>(t1) < get<0>(t2); // or use a custom compare function
});
I wanted to sort tuple multiple times so I wrote this code:我想多次对元组进行排序,所以我写了这段代码:
int k = 10;
while(k--){
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
return get<k>(t1) < get<k>(t2); // or use a custom compare function
});
}
but I get error error: 'k' is not captured
.但我收到错误
error: 'k' is not captured
。 I tried to do it in this way:我试图这样做:
int k = 10;
while(k--){
std::sort(begin(v), end(v), [&k](auto const &t1, auto const &t2) {
return get<k>(t1) < get<k>(t2); // or use a custom compare function
});
}
but it is not the proper way and error error: the value of 'k' is not usable in a constant expression
occurs.但它不是正确的方法和错误
error: the value of 'k' is not usable in a constant expression
。
How to capture k
variable?如何捕获
k
变量?
As mch said in the comment, the problem is that k
is not a compile time constant.正如 mch 在评论中所说,问题在于
k
不是编译时常量。
For a compile time constant, to iterate from N
to 0
, you may need template and recursion:对于编译时常量,要从
N
迭代到0
,您可能需要模板和递归:
#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 . std::get
只接受一个模板参数,它是一个表达式,其值可以在编译时计算。 You can't use k
, because it is a variable that changes value.你不能使用
k
,因为它是一个改变值的变量。
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.正如我在评论中所写的那样,我知道
const int = 3
会隐藏 lambda 表达式之外的k
值,但是这个示例表明get
在收到编译时间常量值时会起作用。 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.例如,如果您尝试设置
k = 5
,例如其中v
只有 4 个元组参数,编译器将给出错误,因为它知道这超出了范围。
The following code will give an error, but if k
is set to 3, it will work下面的代码会报错,但是如果
k
设置为3就可以了
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
});
#include <tuple>
#include <utility>
#include <cstddef>
#include <algorithm>
#include <cstddef>
#include <iterator>
template <std::size_t I, typename It, typename F>
void sort_tuple(It it, It end, F f)
{
std::stable_sort(it, end, [f](const auto& t1, const auto& t2)
{
return f(std::get<I>(t1), std::get<I>(t2));
});
}
template <typename It, typename F, std::size_t... Is>
void sort_tuple(It it, It end, F f, std::index_sequence<Is...>)
{
int dummy[] = { 0, (sort_tuple<sizeof...(Is) - Is - 1>(it, end, f), 0)... };
static_cast<void>(dummy);
}
template <typename It, typename F>
void sort_tuple(It it, It end, F f)
{
sort_tuple(it, end, f, std::make_index_sequence<
std::tuple_size<typename std::iterator_traits<It>::value_type>::value
>{});
}
Test:测试:
std::vector<std::tuple<int, int, int>> v{ {2,1,2}, {2,2,2}, {3,2,1}
, {1,1,1}, {1,2,1}, {2,2,1} };
sort_tuple(begin(v), end(v), [](const auto& t1, const auto& t2)
{
return t1 < t2;
});
for (auto& t : v)
{
std::cout << std::get<0>(t) << " " << std::get<1>(t) << " " << std::get<2>(t) << std::endl;
}
You are using k
as a template argument so it must be available at compile time.您使用
k
作为模板参数,因此它必须在编译时可用。 One way to do this by making it a constexpr
:通过使其成为
constexpr
来做到这一点的一种方法:
constexpr int k = 1;
int j = k;
while(j--){
std::sort(begin(v), end(v), [&k](auto const &t1, auto const &t2) {
return get<k>(t1) < get<k>(t2); // or use a custom compare function
})
}
Template non-type arguments must be compile time constants.模板非类型参数必须是编译时常量。
int k=0;
is not a compile time constant.不是编译时常量。
template<std::size_t...Is>
auto index_over(std::index_sequence<Is...> ={}){
return [](auto&&f)->decltype(auto){
return f( std::integal_constant<std::size_t,Is>{}... );
};
}
template<std::size_t N>
auto index_upto(std::integral_constant<N> ={}){
return index_over(std::make_index_sequence<N>{});
}
these are helpers to get efficient compile time values from 0 up to N-1
.这些是从 0 到
N-1
获得有效编译时间值的助手。
auto foreacher=[](auto&&f){
return [f](auto&&...args){
using discard=int[];
(void)discard{0,(void(
f(decltype(args)(args))
),0)...};
};
};
the above is obscure c++14 to replace short c++17 code.上面是晦涩的c++14替换短的c++17代码。
foreacher(f)
returns a function g
. foreacher(f)
返回一个函数g
。 g(a,b,c)
does f(a)
then f(b)
then f(c)
. g(a,b,c)
执行f(a)
然后f(b)
然后f(c)
。
Now glue it together:现在把它粘在一起:
auto sort_v_by_k=[&](auto k){
std::sort(begin(v), end(v), [](auto const &t1, auto const &t2) {
return get<k>(t1) < get<k>(t2); // or use a custom compare function
});
};
index_upto<11>()( foreacher( [&](auto k){
sort_v_by_k( std::integral_constant<std::size_t, 11-k >{} );
}));
and ignoring typos, done.并忽略错别字,完成。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.