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帮助你。