boost是否具有比STL更简单的set操作的数据types?
我发现C ++的STL方法做简单的集合操作非常笨重。 例如,要find两组之间的区别:
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;
boost是否提供了一个可以减less上述例子的替代类:
set_type<int> newUserIds = currentUserIds.difference(mPreviousUserIds); set_type<int> missingUserIds = mPreviousUserIds.difference(currentUserIds);
(类似于Qt中的QSet ,以这种方式覆盖operator-
)。
请参阅升压范围集algorithm 。 他们仍然期望输出迭代器。
不。 但我在这里是如何清理它。
首先,将基于迭代器的函数重写为基于范围的函数。 这一半你的样板。
其次,让他们返回容器构build器而不是插入迭代器:这给你有效的赋值语法。
第三,也许太过分了,把它们写成指定的操作符。
最终的结果是你得到:
set<int> s = a *intersect* b; set<int> s2 = c -difference- s; set<int> s3 = a *_union_* (b *intersect* s -difference- s2);
…在其他地方写了一堆样板代码之后。
据我所知,助推做第一步。
但是,上述三个阶段中的每一个都会显着降低您的样板。
容器制造商:
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_) {} };
这需要编写is_back_insertable
(相当标准的SFINAE)。
你包装你的基于范围的(或基于迭代器的)仿函数,它将最后一个参数作为back_insert_iterator,并使用std::bind
绑定input参数,使最后一个空闲。 然后将其传递给container_builder
,并将其返回。
然后, container_builder
可以被隐式转换为接受std::back_inserter
(或者拥有自己的ADL back_inserter
)的容器,并且在每个std
容器上move
语义使得构造 – 然后返回非常高效。
这是我的十几行命名操作符库:
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) ); } }
使用它来实现vector *concat* vector
实例 。 它只支持一个操作员,但是扩展起来很简单。 对于严重的使用,我build议有一个times
函数,默认情况下, invoke
*blah*
, add
+blah+
,等等。 <blah>
可以直接调用invoke
。
然后客户端程序员可以重载一个特定于操作符的重载,它可以工作,或者一般的invoke
。
下面是一个类似的库,用于在元组返回函数和期货中实现*then*
。
这里是*in*
一个原始*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;
活的例子 。
不,我认为它永远不会有这样的事情,这是C ++中的一个通用原则,即当你有一个非成员函数来完成这个工作时,永远不会让这个函数成为一个成员。 所以不能这样,但可能是Boost :: Range帮助你。