:stlの各コレクションタイプにfor_eachメンバー関数がないのはなぜですか?たとえば
std::for_each(v.begin(), v.end(), [](int i) { printf("%d\n", i); });
は、このようなメンバ関数は、標準から欠落している正当な理由がある:一般的に使用されるよりもはるかにエレガントで読みやすい場合
v.for_each([](int i) { printf("%d\n", i); });
?
:stlの各コレクションタイプにfor_eachメンバー関数がないのはなぜですか?たとえば
std::for_each(v.begin(), v.end(), [](int i) { printf("%d\n", i); });
は、このようなメンバ関数は、標準から欠落している正当な理由がある:一般的に使用されるよりもはるかにエレガントで読みやすい場合
v.for_each([](int i) { printf("%d\n", i); });
?
これはライブラリ全体の標準的な設計理念です。アルゴリズムとコンテナを分離します。
MフィーチャとN個のコンテナがある場合は、すべてのコンテナYに対してすべてのフィーチャXを実装し、M * N実装に導く必要があります。
イテレータを使用し、コンテナではなくイテレータでアルゴリズムを動作させることで、MアルゴリズムとNイテレータインターフェイスを実装するだけで済みます。
この分離はまた、アプリケーションの無限に広い範囲があることを意味し:アルゴリズムはちょうどすべてのライブラリコンテナに使用することはできませんが、しかし、誰が書いてイテレータを装備することを決定したことを、任意のコンテナ、現在または将来ののため。有限と無限の再利用はかなりの議論です!また、一般的なフリー・インターフェースでアルゴリズムを呼び出すことはコストを追加しません。
ミックスインを使用してこの問題を緩和することができます。一般的なミックスインを書くことができます。 – Puppy
@DeadMG:どのようにして、正規表現マッチやディレクトリトラバーサルのコレクションに対してfor-eachを行うには、どうやってミキシングを使用しますか? –
コンテナはミックスインを継承します。ミックスインは、フードのイテレータを使用して機能を提供します。オブジェクトがiteratorを正確に提供している限り、mixinはそのサポートをOPに表示されたインタフェースで単純なメンバ関数に変換できます。さらに、実際には*より*一般的です。たとえば、 'std :: list'のように、コンテナクラスの機能を自分でオーバーライドすることができるからです。 – Puppy
単純な事実は、言語が多くの機能を提供していない時代からの標準ライブラリの設計であり、CRTPベースのミックスインのような多くのデザインは今のところ共通していないということです。これは、スタンダードライブラリが作成されたときに明らかになった優れたデザインが実装可能でも設計可能でもないことを意味します。
イテレータは非常に一般的な実装ですが、冗長な汎用インターフェイスを作成します。私は、ライブラリ設計の問題を解決し、それを見直す代わりに、問題の小さなサブセットのための特別なケースの言語機能を導入したのは悲しいことです。
将来のコンテナや将来のアルゴリズムに適応できるmixinの例を少し見せてください。 –
@Kerrek:そうする必要はありません。私たちは、将来のアルゴリズムのための既存のサポートを使用することができ、将来のコンテナはそれから継承することができ、最も使用されているアルゴリズムに対してより良いものを得ることができます。 – Puppy
私は参照してください。まあ、これを提供することはいいですね。このようなサウンドは、オプションの機能セットとして追加することができます... –
template <class InputIterator, class UnaryFunction>
UnaryFunction for_each(InputIterator first, InputIterator last, UnaryFunction f);
あなたはfor_eachは、互換性のある入力イテレータ提供することができます任意のSTLコンテナので、パラメータのように入力イテレータを取る見ることができるように(入力イテレータから離れて意味を、それはまた、イテレータなど双方向、ランダムアクセスすることができる)になりますstd :: for_eachと互換性があります。この方法を設計することにより、より洗練されたデータ型(コンテナ)からの包括的な個別アルゴリズム& generic。
なぜあなたはそれを必要としますか?
メンバ関数は、実装がより効率化できる場合にのみ使用されます(set :: findは、集合のstd :: find()より効率的です)。
PSああ、あなたは、.end()
通話途中、.begin()
ユビキタス避けるBoost Range Algorithms使用したい場合。
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/pending/integer_range.hpp>
using namespace boost::adaptors;
static int mod7(int v)
{ return v % 7; }
int main()
{
std::vector<int> v;
boost::copy(
boost::make_integer_range(1,100) | transformed(mod7),
std::back_inserter(v));
boost::sort(v);
boost::copy(
v | reversed | uniqued,
std::ostream_iterator<int>(std::cout, ", "));
}
なぜあなたがそれを必要とする:甘い糖衣構文
ランダムブースト範囲は、サンプルに影響を与えましたか?メンバー関数は、実装がより効率的になる場合にのみ目的を果たします(set :: findは、集合のstd :: find()より効率的です)。ああ、ユビキタスな '.begin()'やen '.end()'コールを避けたいのであれば、[Boost Range Algorithms](http://www.boost.org/doc/libs/1_47_0/libs/)を使ってください。 range/doc/html/range/reference/algorithms/introduction.html)。甘い構文砂糖 – sehe
@sehe:または* less *効率的、 'std :: list :: sort()'のように: –
@Kerrek: 'std :: list :: sort'は特別で、' std :: sort'です。 'RandomAccessIterator'が必要なので、リストではうまくいかないでしょう。 –