0

特定の要素のロジックが現在のインデックスに依存するため、std::for_each を使用できないことがよくあります。そのために、メインのファンクターをラップして現在のインデックスを渡すファンクター クラスを発明しました。理想的には、ラムダ式で使用したいと考えています。私が作成したクラスは安全で効果的ですか? より良い解決策はありますか?ラッパーの演算子 () がラムダ式の型を返すようにしたかったのですが、それがわかりませんでした。また、インデックスにはどのタイプを使用すればよいですか? メイン ファンクターを値または参照でラッパーに格納する必要がありますか?

ありがとう!

template<class FUNC>
class IndexFunctor
{
public:
    typedef FUNC FUNC_T;

    explicit IndexFunctor(const FUNC_T& func) : func(func), index(0) {}

    // how can this return the return type of func?
    template<class T>
    void operator ()(T& param)
    {
        func(index++, param);
    }

    const FUNC_T& GetFunctor() const
    {
        return func;
    }

    int GetIndex() const
    {
        return index;
    }

    void SetIndex(int index)
    {
        this->index = index;
    }

private:
    FUNC_T func;
    int index;
};

template<class FUNC>
IndexFunctor<FUNC> with_index(const FUNC& func)
{
    return IndexFunctor<FUNC>(func);
}

void somefunc()
{
    std::vector<int> v(10);
    std::for_each(v.begin(), v.end(), with_index([](int index, int x){ std::cout << "[" << index << "]=" << x << std::endl; }));
}
4

4 に答える 4

4

これは安全なはずですが、インデックス付きの for-each を自分で作成するのはかなり簡単です。

template <typename TInputIterator, typename TFunc>
TFunc counted_for_each(TInputIterator first, TInputIterator last, TFunc func)
{
    for (size_t i = 0; first != last; ++first)
    {
        func(i++, *first);
    }

    return func;
}

より少ないコードで同じことを達成します。

于 2013-07-21T21:35:04.943 に答える
4

std::for_each最初からの問題は、 ?を使用してインデックス/カウンターを追跡したいということでした。その場合の 1 つの解決策は、単純にカウンター変数を使用して、たとえばラムダ式でそれをキャプチャーさせることです。

std::vector<int> v{ 1, 2, 3 };

std::vector<int>::size_type i = 0;

std::for_each(begin(v), end(v), [i] (int x) mutable {
    std::cout << "[" << i++ << "]=" << x << std::endl;
});

または、次のように単純に行うこともできます。

std::vector<int>::size_type i = 0;
for (auto itr = begin(v); itr != end(v); ++itr) {
    std::cout << "[" << i++ << "]=" << *itr << std::endl;
}

C++11 で範囲ベースの for ループを使用すると、次のように簡略化できます。

std::vector<int>::size_type i = 0;
for (auto itr : v) {
    std::cout << "[" << i++ << "]=" << itr << std::endl;
}

注:上記の最後の 2 つの例では、for ループを実行するたびにインデックス カウンターを 0 にリセットすることを忘れないでください。

更新:ループの外側にインデックス変数を持ちたくないが、インデックスを追跡しながら部分範囲を反復処理する場合は、次のstd::distanceように使用してインデックスを計算できます。

for (auto itr = begin(v); itr != end(v); ++itr) {
    std::cout << "[" << std::distance(begin(v),itr) << "]=" << *itr << std::endl;
}

また、C++14 Generalized Lambda Capture Expressions を使用すると、外側のスコープでカウンター vairable を省略し、初期化式を使用iしてラムダのメンバーとして作成できます。

std::for_each(begin(v), end(v), [i = 0] (int x) mutable {
    std::cout << "[" << i++ << "]=" << x << std::endl;
});
于 2013-07-21T21:55:32.777 に答える
3

私の意見では、範囲ベースのループでstd::for_eachはほとんど時代遅れです。for( : )

そのためにも、range_view template範囲ベースのfor( : )ループで動作する があります。Aは、イテレータを返す メソッドとメソッドをrange_view持つ単純な構造です。このようなオブジェクトは、範囲ベースの for ループに渡すことができます。begin()end()

template<typename Iterator>
struct range_view {
  Iterator b, e;
  Iterator begin() const { return b; }
  Iterator end() const { return e; }
};
template<typename Iterator>
range_view<Iterator> make_range_view( Iterator b, Iterator e ) {
  return {b,e};
}
template<typename Container>
auto make_range_view( Container&& c )
-> decltype( make_range_view( std::begin(c), std::end(c) ) )
{   return ( make_range_view( std::begin(c), std::end(c) ) ); }

インデックスが必要な場合は、indexes範囲を使用するか、非常に熱心な場合はzip、インデックス範囲と元のコンテナーで範囲アダプターを使用します (タプルの範囲を生成します)。 indexes連続した整数に対するイテレータ (boostそのような型があります) であり、zip2 つの範囲またはコンテナを取り、データの範囲tupleまたはpairs を返す操作です。

これで、代わりにあなたのものを修正できます。()完全な転送とauto->decltype戻り値を使用するようにアップグレードしてください。しかし、私は気にしません。stdアルゴリズムにはその場所がありますが、そのfor_each価値があることはめったにありません。

于 2013-07-21T21:31:02.820 に答える