forループで異なる型の2つの変数を宣言することは可能ですか?


240

C ++のforループの初期化本体で異なる型の2つの変数を宣言することは可能ですか?

例えば:

for(int i=0,j=0 ...

2つの整数を定義します。初期化本体でintとを定義できますcharか?これはどのように行われますか?


3
-std=c++0xの形式でg ++-4.4()でfor(auto i=0, j=0.0; ...可能ですが、この可能性はc ++ 0xテキストと一致するようにg ++-4.5で削除されました。
rafak

回答:


133

C ++ 17はい!構造化バインディング宣言を使用する必要があります。この構文は、gccとclangで何年もサポートされています(gcc-7とclang-4.0以降)(clang live example)。これにより、次のようにタプルを解凍できます。

for (auto [i, f, s] = std::tuple{1, 1.0, std::string{"ab"}}; i < N; ++i, f += 1.5) {
    // ...
}

上記はあなたに与えるでしょう:

  • int i に設定 1
  • double f に設定 1.0
  • std::string s に設定 "ab"

#include <tuple>この種の宣言には必ず注意してください。

タイプに名前を付けたい場合tuplestd::string、と同じようにすべてを入力して、内に正確なタイプを指定できます。例えば:

auto [vec, i32] = std::tuple{std::vector<int>{3, 4, 5}, std::int32_t{12}}

これの特定のアプリケーションは、マップを反復して、キーと値を取得することです。

std::unordered_map<K, V> m = { /*...*/ };
for (auto& [key, value] : m) {
   // ...
}

こちらのライブ例をご覧ください


C ++ 14:type-basedを追加することで、C ++ 11(下記)と同じことができますstd::get。だから、代わりにstd::get<0>(t)以下の例では、あなたが持つことができますstd::get<int>(t)


C ++ 11std::make_pairこれを実行できるほかstd::make_tuple、3つ以上のオブジェクトに対しても実行できます。

for (auto p = std::make_pair(5, std::string("Hello World")); p.first < 10; ++p.first) {
    std::cout << p.second << std::endl;
}

std::make_pair2つの引数をで返しstd::pairます。要素には.firstおよびを使用してアクセスできます.second

3つ以上のオブジェクトの場合は、 std::tuple

for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
        std::get<0>(t) < 10;
        ++std::get<0>(t)) {
    std::cout << std::get<1>(t) << std::endl; // cout Hello world
    std::get<2>(t).push_back(std::get<0>(t)); // add counter value to the vector
}

std::make_tuple任意の数の引数のタプルを構築する可変テンプレートです(もちろん、いくつかの技術的な制限があります)。要素は、インデックスを使用してアクセスできますstd::get<INDEX>(tuple_object)

ループのための体の中ですることができます簡単にオブジェクトのエイリアス、あなたはまだ使用する必要があるものの.firstまたはstd::getループ条件と更新式のためにのために

for (auto t = std::make_tuple(0, std::string("Hello world"), std::vector<int>{});
        std::get<0>(t) < 10;
        ++std::get<0>(t)) {
    auto& i = std::get<0>(t);
    auto& s = std::get<1>(t);
    auto& v = std::get<2>(t);
    std::cout << s << std::endl; // cout Hello world
    v.push_back(i); // add counter value to the vector
}

C ++ 98およびC ++ 03のタイプに明示的に名前を付けることができstd::pairます。ただし、これを3つ以上のタイプに一般化する標準的な方法はありません。

for (std::pair<int, std::string> p(5, "Hello World"); p.first < 10; ++p.first) {
    std::cout << p.second << std::endl;
}

5
C ++ 17を実行している場合は、をドロップしてmake_を書き込むこともできますstd::pair(1, 1.0)
Marc Glisse、2016年

毛深いC ++ 14スタイルのタプル/ペアビジネス-すべて(おそらく、賛成)は良いですが、奇妙に見えます:)
mlvljr

3
要約すると、可能ですが、美しくはありません。
一部のプログラマー、

ええ、きれいではありませんが、ドープです!タプルっぽいものを絶対に楽しんだ。:)しかし、実際にはそれはC ++のforループの非常に直感的でない構文上の品質であり、最終的にGoogledが必要なものを理解するのに30分以上頭痛を与えました...
aderchox

@aderchox誤解を明確にできれば答えを更新できます
Ryan Haining

276

いいえ-しかし、技術的には回避策があります(強制されない限り、実際に使用するわけではありません)。

for(struct { int a; char b; } s = { 0, 'a' } ; s.a < 5 ; ++s.a) 
{
    std::cout << s.a << " " << s.b << std::endl;
}

3
これはVS 2008ではコンパイルされませんが、オンラインのコモーでコンパイルされます;-)
JRL

7
@JRL:ああ、VS2005も。VC ++のさらに別の非準拠機能は私が推測します。
Georg Fritzsche、2010

3
Perlで同等のことを行いました。ただし、C ++のコードレビューでこのようなことをこっそり試したことはありません。
ジョン

21
c ++ 11を使用すると、デフォルト値を使用してこの例を短くすることができますstruct { int a=0; char b='a'; } s;
Ryan Haining

1
この回答は回答の要件を満たしていますが、読みやすさの観点から、私は@MKを好みます。の答え。MKのソリューションは、中括弧を追加することでスコープにも対応しています。
Trevor Boyd Smith

221

不可能ですが、次のことができます。

float f;
int i;
for (i = 0,f = 0.0; i < 5; i++)
{
  //...
}

または、明示的の範囲を限定fし、i追加のブラケットを使用しました:

{
    float f; 
    int i;
    for (i = 0,f = 0.0; i < 5; i++)
    {
       //...
    }
}

私はこれが非常に古い質問であることを知っていますが、2番目の例のように、周りの余分な角括弧を使用してなぜそれを行うのか説明できますか?
フォード

13
@fizzisistを使用すると、fとiのスコープを、コードが使用される部分のみに明示的に制限できます。
MK。

1
@MK。ありがとう、それは私が疑ったことです。私はそれを説明するためにあなたの答えを編集しました。
フォード

1つだけ質問:なぜこれが好きなのですか?:O
rohan-patel 2013年

「int a = 0、b = 4」のように機能するため、私は想定しています。そうは言っても、fとiのスコープ指定は、それらの名前の再利用を防ぐためにのみ役立つでしょう(これは正当な理由です)が、生成されたコードは通常(この場合)現代のコンパイラーでも同じです。
Asu、

14

初期化で複数の型を宣言することはできませんが、複数の型に割り当てることができますEG

{
   int i;
   char x;
   for(i = 0, x = 'p'; ...){
      ...
   }
}

独自のスコープで宣言してください。


3

最善のアプローチは西安の答えだと思います

だが...


#ネストされたforループ

このアプローチはダーティですが、すべてのバージョンで解決できます。

そのため、マクロ関数でよく使用します。

for(int _int=0, /* make local variable */ \
    loopOnce=true; loopOnce==true; loopOnce=false)

    for(char _char=0; _char<3; _char++)
    {
        // do anything with
        // _int, _char
    }

追加1。

それはまたに使用することができますdeclare local variablesinitialize global variables

float globalFloat;

for(int localInt=0, /* decalre local variable */ \
    _=1;_;_=0)

    for(globalFloat=2.f; localInt<3; localInt++) /* initialize global variable */
    {
        // do.
    }

追加2。

良い例:マクロ機能付き。

(for-loop-macroであるため、最善のアプローチを使用できない場合)

#define for_two_decl(_decl_1, _decl_2, cond, incr) \
for(_decl_1, _=1;_;_=0)\
    for(_decl_2; (cond); (incr))


    for_two_decl(int i=0, char c=0, i<3, i++)
    {
        // your body with
        // i, c
    }

#ifステートメントトリック

if (A* a=nullptr);
else
    for(...) // a is visible

0またはnullptrに初期化する場合は、このトリックを使用できます。

読みづらいのでお勧めしません。

バグのようです。


ある人が他の人とどう違うかを私が驚かせることは決して止まりません。私はそのような奇妙なことを考えたことはなかったでしょう。面白いアイデア。
パーソンパーソンII

1

複数のforループのネストを含む別の方法については、「for ループで2つの型の変数を定義する方法はありますか?」を参照してください。Georgの「構造トリック」に対する他の方法の利点は、(1)静的および非静的ローカル変数の混合を可能にし、(2)コピー不可能な変数を可能にすることです。欠点は、読みにくく、効率が悪い可能性があることです。


-2

マクロを定義します。

#define FOR( typeX,x,valueX,  typeY,y,valueY,  condition, increments) typeX x; typeY y; for(x=valueX,y=valueY;condition;increments)

FOR(int,i,0,  int,f,0.0,  i < 5, i++)
{
  //...
}

この方法でも、変数のスコープはforループ内にないことに注意してください。


{とを使用して別のスコープでマクロのコードをラップすることで、この制限を簡単に克服できます}
Nathan Osman

4
いいえ、できませんでした。彼のマクロはループ本体をラップしません。追加の開始ブラケットを追加することもできますが、マクロを使用する場合は「追加」の終了ブラケットが必要になります。
ジョン

3
興味深いアイデアですが、これを検討する前に、他の回答をすぐに使用します。
gregn3

-2

また、C ++では以下のように使用できます。

int j=3;
int i=2;
for (; i<n && j<n ; j=j+2, i=i+2){
  // your code
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.