我听说你喜欢lambda表达式。
auto with_index_into = [](auto&v){
return [&](auto&& f){
return [&,f=decltype(f)(f)](auto& e){
return f( std::addressof(e)-v.data(), e );
};
};
};
这可能会有所帮助。它需要一个支持
.data()
的容器,然后返回一个类型为
((Index,E&)->X)->(E&->X)
的Lambda表达式 - 返回的Lambda表达式将索引元素访问者转换为元素访问者。有点像Lambda柔道。
template<class C, class Test>
auto erase_if( C& c, Test&& test) {
using std::begin; using std::end;
auto it=std::remove_if(begin(c),end(c),test);
if (it==end(c)) return false;
c.erase(it, end(c));
return true;
}
因为我厌恶在客户端代码中使用删除擦除惯用语。
现在这段代码非常简洁:
erase_if( v1, with_index_into(v1)(
[](std::size_t i, auto&e){
return !v2[i];
}
));
移除/删除中的移动限制
应该意味着它在元素原始位置上调用lambda函数。
我们可以通过更基本的步骤来完成这个过程。 在中间部分会变得复杂...
首先,我们需要一个小型的命名运算符库:
namespace named_operator {
template<class D>struct make_operator{};
enum class lhs_token {
star = '*',
non_char_tokens_start = (unsigned char)-1,
arrow_star,
};
template<class T, lhs_token, class O> struct half_apply { T&& lhs; };
template<class Lhs, class Op>
half_apply<Lhs, lhs_token::star, Op>
operator*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op>
half_apply<Lhs, lhs_token::arrow_star, Op>
operator->*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, lhs_token::star, Op>&& lhs, Rhs&& rhs )
{
return named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, lhs_token::arrow_star, Op>&& lhs, Rhs&& rhs )
{
return named_next( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
}
现在我们定义
then
:
namespace lambda_then {
struct then_t:named_operator::make_operator<then_t> {} then;
template<class Lhs, class Rhs>
auto named_next( Lhs&& lhs, then_t, Rhs&& rhs ) {
return
[lhs=std::forward<Lhs>(lhs), rhs=std::forward<Rhs>(rhs)]
(auto&&...args)->decltype(auto)
{
return rhs( lhs( decltype(args)(args)... ) );
};
}
}
using lambda_then::then;
这段文字涉及到 IT 技术,其中定义了一个名为“then”的标记,它的含义是,lambda1 ->*then* lambda2
返回一个函数对象,该对象接收参数并将其传递给 lambda1,然后将返回值传递给 lambda2。
接下来我们定义了 to_index(container)
:
template<class C>
auto index_in( C& c ) {
return [&](auto& e){
return std::addressof(e)-c.data();
};
}
我们还保留了上述的`erase_if`函数。
这会导致:
erase_if( v1,
index_in(v1)
->*then*
[&](auto i){
return !v2[i];
}
);
solving your problem (live example).
vector::erase()
的时间复杂度是线性的。使用 erase() 删除每个有问题的元素会导致二次时间复杂度。vector::erase()
还会使后续元素的所有指针、引用和迭代器无效。这个函数速度慢,不安全,通常应该避免使用。(我希望你不会说“那就用列表”。)除此之外,我们可能需要有问题的元素来确定其他元素的有效性。 - user31264erase
,并且它们也仅用于数组的最后部分。这种特殊情况下的vector::erase
操作既快速又安全。 - user31264