不。但我这里是如何清理它。
首先,将基于迭代器的函数重写为基于范围的函数。这将您的样板文件减半。
其次,让它们返回容器构建器而不是插入迭代器:这为您提供了高效的赋值语法。
第三,可能太过分了,把它们写成命名操作符。
最终的结果是你得到:
set<int> s = a *intersect* b;
set<int> s2 = c -difference- s;
set<int> s3 = a *_union_* (b *intersect* s -difference- s2);
...在其他地方编写了大量样板代码之后。
据我所知,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_) {}
};
这需要写is_back_insertable(相当标准的SFINAE)。
您包装基于范围(或基于迭代器)的函子,该函子将 back_insert_iterator 作为最后一个参数,并使用 std::bind 绑定输入参数,使最后一个空闲。然后将其传递给container_builder,并返回。
container_builder 然后可以隐式转换为任何接受std::back_inserter(或具有自己的ADL back_inserter)的容器,并且每个move 容器上的move 语义使得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) );
}
}
live example 使用它来实现vector *concat* vector。它只支持一个运算符,但扩展它很容易。对于严肃的使用,我建议有一个times 函数,默认情况下调用invoke 为*blah*,一个add 为+blah+ 执行相同的操作,等等。<blah> 可以直接调用invoke .
然后客户端程序员可以重载一个特定于运算符的重载并且它可以工作,或者一般的invoke。
Here is a similar library being used to implement *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;
live example.