44

オブジェクトのベクトルがあり、range-forループを使用して反復処理しています。次のように、オブジェクトから関数を印刷するために使用しています。

vector<thisObject> storedValues;
//put stuff in storedValues
for(auto i:storedValues)
{
   cout<<i.function();
}

しかし、私もインデックスを印刷したいと思います。私の希望する出力は次のとおりです。

1: value
2: value
//etc

毎回増やしていくカウンターを使うつもりでしたが、なかなか効率が悪いようでした。もっと良い方法はありますか?

4

6 に答える 6

44

できません。インデックスはベクトルに対する特定の概念であり、コレクションの一般的なプロパティではありません。一方、範囲ベースのループは、コレクションのすべての要素を反復処理するための一般的なメカニズムです。

特定のコンテナ実装の詳細を使用したい場合は、通常のループを使用してください。

for (std::size_t i = 0, e = v.size(); i != e; ++i) { /* ... */ }

要点を繰り返すと、範囲ベースのループは、コレクション自体は重要ではなく、コンテナがループ本体内で言及されることはない、任意のコレクションの各要素を操作するためのものです。これはツールボックス内の単なる別のツールであり、絶対にすべてに使用する必要はありません。対照的に、コレクションを変更する場合(たとえば、要素を削除またはシャッフルする場合)、またはコレクションの構造に関する特定の情報を使用する場合は、通常のループを使用します。

于 2012-09-12T23:46:15.253 に答える
21

これを比較的クリーンな方法で処理するプリプロセッサマクロ(@Artyerによって大幅に簡略化されたもの)を作成しました。

#define for_indexed(...) for_indexed_v(i, __VA_ARGS__)
#define for_indexed_v(v, ...) if (std::size_t v = -1) for (__VA_ARGS__) if ((++v, true))

使用例:

std::vector<int> v{1, 2, 3};
for_indexed (auto const& item : v) {
    if (i > 0) std::cout << ", ";
    std::cout << i << ": " << item;
}

別のループ変数を使用するには:

for_indexed_v (my_counter, auto const& item : v) ...

追加の制御フローロジックは、デバッグ以外のビルドでは最適化する必要があります。比較的読みやすいループ構文が残ります。

2020年の注意:マクロトリックの代わりにラムダベースのソリューションを使用する方がおそらく賢明でしょう。もちろん、構文は「クリーン」ではありませんが、実際のC++構文として認識できるという利点があります。選択はあなた次第です。

更新2017/05/28break;ステートメントが正しく機能するように
更新2019/01/28:単語が有効な変数名にforなるようにマクロ名を入力します。競合が発生することはないとindexed思います。アップデート2020/12/23:大幅に簡素化(@Artyerに感謝)for_indexed

于 2017-04-05T00:50:27.990 に答える
15

range-v3enumerateのビューを使用できます:

std::vector<thisObject> storedValues;
for (auto const& [idx, value] : storedValues | ranges::views::enumerate) {
  std::cout << idx << ": " << value << '\n';
}

C ++ 20では、範囲forループに追加の初期化が導入されます。

std::vector<thisObject> storedValues;
for (size_t idx = 0; auto value : storedValues) {
  std::cout << idx << ": " << value << '\n';
  ++idx;
}
于 2020-02-13T14:19:48.650 に答える
13

を使用しrange-v3ます。Range-v3は、ISO C++委員会のメンバーであるEricNieblerによって設計および実装された次世代の範囲ライブラリであり、将来的にC++標準に統合される予定です。

OPを使用することによりrange-v3、問題は簡単に解決できます。

using ranges::v3::view::zip;
using ranges::v3::view::ints;

for(auto &&[i, idx]: zip(storedValues, ints(0u))){
    std::cout << idx << ": " << i.function() << '\n';
}

このコードをコンパイルするには、構造化バインディング構文だけでなく、の戻り型とbeginend戻り値の関数がranges::v3::view::zip異なるという事実のために、C++17以降をサポートするコンパイラが必要になります。

ここでオンラインの例を見ることができます。のドキュメントrange-v3ここにあり、ソースコード自体はここでホストされています。MSVCコンパイラを使用している場合は、ここも参照してください。

于 2017-10-22T17:38:13.050 に答える
4

正直なところ、これは非常に単純です。アドレスを減算できることを理解する必要があります:)

&iはメモリ内のアドレスを参照し、定義されたベクトル型の整数を保持しているため、インデックスからインデックスへと4ずつ増加します。ここで、&values [0]は最初のポイントを参照します。2つのアドレスを減算すると、2つのアドレスの差はそれぞれ0,4,8,12になりますが、実際には、整数型のサイズ(通常は4バイト)を減算します。したがって、対応して0 = 0番目の整数、4 = 1番目の整数、8 = 2番目の整数、12=3番目の整数

ここにそれはベクトルにあります

vector<int> values = {10,30,9,8};

for(auto &i: values) {

cout << "index: " <<  &i  - &values[0]; 
cout << "\tvalue: " << i << endl;

}

これは通常の配列用で、ほとんど同じです

int values[]= {10,30,9,8};

for(auto &i: values) {

cout << "index: " <<  &i  - &values[0];
cout << "\tvalue: " << i << endl;

}

これはC++11用であることに注意してください。g++を使用している場合は、コンパイルに-std = c++11パラメーターを使用することを忘れないでください。

于 2018-07-13T07:19:55.740 に答える
3

これは、c++17のプリプロセッサマクロバージョンの更新バージョンです。Clangは、インデックスを使用してループを手動で作成する場合と比較して、同一のデバッグおよび最適化されたコードを生成します。MSVCは同一の最適化されたコードを生成しますが、デバッグにいくつかの追加の命令を追加します。

#define for_index(...) for_index_v(i, __VA_ARGS__)
#define for_index_v(i, ...) if (size_t i##_next = 0; true) for (__VA_ARGS__) if (size_t i = i##_next++; true)

私はMSVCがデバッグビルドに追加していた余分なコードを掘り下げようとしていましたが、その目的が何であるかはよくわかりません。ループの開始時に以下を追加します。

        xor     eax, eax
        cmp     eax, 1
        je      $LN5@for_i

これはループを完全にスキップします。使用例:https ://godbolt.org/z/VTWhgT

于 2019-05-14T05:48:46.700 に答える