Tim*_* MB 26 c++ boost stl set
我发现使用C++ STL方法进行简单的集合操作非常笨重.例如,要找到两组之间的差异:
std::set<int> newUserIds;
set_difference(currentUserIds.begin(), currentUserIds.end(), mPreviousUserIds.begin(), mPreviousUserIds.end(), std::inserter(newUserIds, newUserIds.end()));
std::set<int> missingUserIds;
set_difference(mPreviousUserIds.begin(), mPreviousUserIds.end(), currentUserIds.begin(), currentUserIds.end(), std::inserter(missingUserIds, missingUserIds.end()));
mPreviousUserIds = currentUserIds;
Run Code Online (Sandbox Code Playgroud)
boost是否提供了一组替代类,可以将上面的示例缩小为:
set_type<int> newUserIds = currentUserIds.difference(mPreviousUserIds);
set_type<int> missingUserIds = mPreviousUserIds.difference(currentUserIds);
Run Code Online (Sandbox Code Playgroud)
(类似于Qt中的QSet,它operator-
以这种方式覆盖.)
Yak*_*ont 83
不.但我在这里是如何清理它.
首先,将基于迭代器的函数重写为基于范围的函数.这使您的样板减半.
其次,让它们返回容器构建器而不是使用插入迭代器:这为您提供了有效的赋值语法.
第三,可能太过分了,把它们写成命名运算符.
最终结果是:
set<int> s = a *intersect* b;
set<int> s2 = c -difference- s;
set<int> s3 = a *_union_* (b *intersect* s -difference- s2);
Run Code Online (Sandbox Code Playgroud)
...在其他地方写了一大堆样板代码之后.
据我所知,boost会做第1步.
但是上述三个阶段中的每个阶段都应该显着降低样板.
容器制造商:
template<typename Functor>
struct container_builder {
Functor f;
template<typename Container, typename=typename std::enable_if<back_insertable<Container>::value>::type>
operator Container() const {
Container retval;
using std::back_inserter;
f( back_inserter(retval) );
return retval;
}
container_builder(Functor const& f_):f(f_) {}
};
Run Code Online (Sandbox Code Playgroud)
这需要写作is_back_insertable
(相当标准的SFINAE).
你包装你的基于范围的(或基于迭代器的)函子,它将back_insert_iterator作为最后一个参数,并用于std::bind
绑定输入参数,使最后一个参数保持空闲.然后将其传递给container_builder
,并将其返回.
container_builder
然后可以隐式地转换为接受std::back_inserter
(或具有自己的ADL back_inserter
)的任何容器,并且move
每个std
容器上的语义使得construct-then-return非常有效.
这是我的十几行命名运算符库:
namespace named_operator {
template<class D>struct make_operator{make_operator(){}};
template<class T, char, class O> struct half_apply { T&& lhs; };
template<class Lhs, class Op>
half_apply<Lhs, '*', Op> operator*( Lhs&& lhs, make_operator<Op> ) {
return {std::forward<Lhs>(lhs)};
}
template<class Lhs, class Op, class Rhs>
auto operator*( half_apply<Lhs, '*', Op>&& lhs, Rhs&& rhs )
-> decltype( named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) ) )
{
return named_invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
}
}
Run Code Online (Sandbox Code Playgroud)
用它来实现的实例vector *concat* vector
.它只支持一个操作员,但扩展它很容易.对于严重的使用,我建议有times
,默认情况下调用函数invoke
的*blah*
,一个add
用于+blah+
做同样的,等 <blah>
可以直接调用invoke
.
然后客户端程序员可以重载特定于操作员的重载,它可以工作,或者一般invoke
.
这是一个类似的库,用于实现*then*
元组返回函数和期货.
这是一个原始的*in*
:
namespace my_op {
struct in_t:named_operator::make_operator<in_t>{};
in_t in;
template<class E, class C>
bool named_invoke( E const& e, in_t, C const& container ) {
using std::begin; using std::end;
return std::find( begin(container), end(container), e ) != end(container);
}
}
using my_op::in;
Run Code Online (Sandbox Code Playgroud)
实例.