いいえ。しかし、私はここでそれをきれいにする方法です。
まず、イテレータベースの関数を範囲ベースの関数として書き直します。これにより、定型文が半分になります。
次に、挿入イテレータを使用するのではなく、コンテナビルダーを返すようにします。これにより、効率的な割り当て構文が得られます。
第三に、おそらくあまりにも遠いので、それらを名前付き演算子として記述します。
最終的な結果は次のとおりです。
set<int> s = a *intersect* b;
set<int> s2 = c -difference- s;
set<int> s3 = a *_union_* (b *intersect* s -difference- s2);
...ボイラープレートコードのボートロードを他の場所に書き込んだ後。
私の知る限り、ブーストはステップ1を実行します。
ただし、上記の3つの段階のそれぞれで、定型文が大幅に削減されます。
コンテナビルダー:
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
セマンティクスstd
により、construct-then-returnが非常に効率的になります。
これが、operatorlibraryという名前の私のダース行です。
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
。1人のオペレーターのみをサポートしますが、拡張は簡単です。times
本格的に使用する場合は、デフォルトでを呼び出す関数、同じことを行うinvoke
forなど が直接呼び出すことができる関数を用意することをお勧めします。*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;
ライブ例。