43

STL アルゴリズムは、C++ で非常に便利なものです。しかし、私を苛立たせていることの 1 つは、それらが構成可能性に欠けているように見えることです。

たとえば、 があり、それをペアのメンバーのみを含むvector<pair<int, int>>に変換したいとします。それはとても簡単です:vector<int>second

std::vector<std::pair<int, int>> values = GetValues();
std::vector<int> result;

std::transform(values.begin(), values.end(), std::back_inserter(result),
    [] (std::pair<int, int> p) { return p.second; });

または、メンバーが偶数vectorのペアのみをフィルタリングしたいかもしれません。firstまた、非常に単純です:

std::vector<std::pair<int, int>> values = GetValues();
std::vector<std::pair<int, int>> result;

std::copy_if(values.begin(), values.end(), std::back_inserter(result),
    [] (std::pair<int, int> p) { return (p.first % 2) == 0; });

しかし、両方をやりたい場合はどうすればよいでしょうか。transform_ifアルゴリズムはなく、両方transformを使用すると、中間結果を保持するためにcopy_if一時的なものを割り当てる必要があるようです:vector

std::vector<std::pair<int, int>> values = GetValues();
std::vector<std::pair<int, int>> temp;
std::vector<int> result;

std::copy_if(values.begin(), values.end(), std::back_inserter(temp),
    [] (std::pair<int, int> p) { return (p.first % 2) == 0; });

std::transform(values.begin(), values.end(), std::back_inserter(result),
    [] (std::pair<int, int> p) { return p.second; });

これは私にはかなり無駄に思えます。一時的なベクトルを回避するために私が考えることができる唯一の方法は、放棄transformcopy_ifて単純に使用することですfor_each(または通常の for ループ、あなたの好みに合ったもの):

std::vector<std::pair<int, int>> values = GetValues();
std::vector<int> result;

std::for_each(values.begin(), values.end(),
    [&result] (std::pair<int, int> p) 
        { if( (p.first % 2) == 0 ) result.push_back(p.second); });

ここで何か不足していますか?一時的なストレージを必要とせずに、2 つの既存の STL アルゴリズムを新しいものに構成する良い方法はありますか?

4

5 に答える 5

25

あなたが正しい。Boost.Rangeアダプターを使用して構成を実現できます。

于 2011-07-19T06:37:20.563 に答える
11

問題は残念ながら構造的なものだと思います

  1. C ++は、2つのイテレータを使用してシーケンスを表します
  2. C++関数は単一値です

したがって、関数は「シーケンス」を返すことができないため、それらをチェーンすることはできません。

オプションは、代わりに単一オブジェクトシーケンスを使用することでした(boostからの範囲アプローチのように)。このようにして、ある処理の結果を別の入力として組み合わせることができます...(1つのオブジェクト-> 1つのオブジェクト)。

代わりに、標準C ++ライブラリでは、処理は(2つのオブジェクト-> 1つのオブジェクト)であり、一時オブジェクトに名前を付けずにこれを連鎖させることはできないことは明らかです。

于 2011-07-19T06:36:42.590 に答える
8

2000年に、問題はすでに指摘されていました。GaryPowellとMartinWeiserは「ビュー」の概念を考案し、「ビューテンプレートライブラリ」という名前を作り出しました。その時は離陸しませんでしたが、その考えは理にかなっています。「ビュー」アダプタは、基本的にオンザフライ変換を適用します。たとえば、を適応させることができますvalue_type

C ++ 0xができたので、この概念はおそらく再検討する必要があります。2000年以来、ジェネリックプログラミングはかなり進歩しています。

たとえば、vector<pair<int, int>> toのvector<int>例を使用してみましょう。それは非常に簡単かもしれません:

std::vector<std::pair<int, int>> values = GetValues();
vtl2::view v (values, [](std::pair<int, int> p) { return p.first }); 
std::vector<int> result(view.begin(), view.end());

または、boost::bindテクニックを使用すると、さらに簡単になります。

std::vector<std::pair<int, int>> values = GetValues();
vtl2::view v (values, &std::pair<int, int>::first); 
std::vector<int> result(view.begin(), view.end());
于 2011-07-19T08:13:20.620 に答える