web-dev-qa-db-ja.com

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

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

例えば:

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

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

208
Nathan Osman

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

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++)
    {
       //...
    }
}
202
MK.

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

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

C++ 17はい!構造化バインディング宣言 。この構文は、gcc-7およびclang-4.0でサポートされています( clang live example )。これにより、次のようにタプルを展開できます。

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

上記はあなたに与えます:

  • int i1に設定
  • double f1.0に設定
  • std::string s"abc"に設定

この種の宣言には必ず#include <Tuple>を使用してください。

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

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

C++ 14:タイプベースのstd::getを追加することで、C++ 11(以下)と同じことができます。したがって、以下の例の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_pairは、std::pairに2つの引数を返します。要素には、.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)を使用して、インデックスから要素にアクセスできます

Forループ本体内では、オブジェクトのエイリアスを簡単に作成できますが、forループ条件と更新式には.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++ 03std::pairの型に明示的に名前を付けることができます。ただし、これを3つ以上のタイプに一般化する標準的な方法はありません。

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

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

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

独自のスコープで宣言するだけです。

14
zmbush

複数のforループをネストする別の方法については、「 forループに2つのタイプの変数を定義する方法はありますか? 」を参照してください。 Georgの「構造トリック」に対する他の方法の利点は、(1)静的なローカル変数と非静的なローカル変数を混在させることができ、(2)コピーできない変数を持つことができることです。欠点は、読み取りがはるかに少なく、効率が低下する可能性があることです。

1
tgoodhart

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

しかし...


#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 variablesおよびinitialize 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に初期化する場合、このトリックを使用できます。

しかし、読みにくいのでこれはお勧めしません。

バグのようです。

0
mgcation

マクロを定義します。

#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ループ内にないことを覚えておいてください。

0
Ryan Favale