web-dev-qa-db-fra.com

Est-il possible de déclarer deux variables de types différents dans une boucle for?

Est-il possible de déclarer deux variables de types différents dans le corps d'initialisation d'une boucle for en C++?

Par exemple:

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

définit deux entiers. Puis-je définir un int et un char dans le corps d'initialisation? Comment cela serait-il fait?

214
Nathan Osman

Pas possible, mais vous pouvez faire:

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

Ou, limitez explicitement la portée de f et i à l'aide de crochets supplémentaires:

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

Non - mais techniquement, il y a un moyen de contourner le problème (pas que je l'utilise réellement à moins d'y être forcé):

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

C++ 17 : Oui! Vous devez utiliser un déclaration de liaison structurée . La syntaxe est prise en charge dans gcc-7 et clang-4.0 ( exemple de clang live ). Cela nous permet de décompresser un tuple comme ceci:

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

Ce qui précède vous donnera:

  • _int i_ défini sur _1_
  • _double f_ défini sur _1.0_
  • _std::string s_ défini sur _"abc"_

Assurez-vous de _#include <Tuple>_ pour ce type de déclaration.

Vous pouvez spécifier les types exacts à l'intérieur de Tuple en les saisissant tous comme je le sais avec le _std::string_, si vous souhaitez nommer un type. Par exemple:

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

C++ 14 : vous pouvez faire la même chose que C++ 11 (ci-dessous) en ajoutant un type _std::get_. Ainsi, au lieu de std::get<0>(t) dans l'exemple ci-dessous, vous pouvez avoir std::get<int>(t).


C++ 11 : std::make_pair vous permet de le faire, ainsi que std::make_Tuple pour plus de deux objets.

_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_ renverra les deux arguments dans un _std::pair_. Les éléments sont accessibles avec _.first_ et _.second_.

Pour plus de deux objets, vous devrez utiliser un _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_ est un modèle variadique qui construira un tuple d'un nombre quelconque d'arguments (avec quelques limitations techniques bien sûr). Les éléments sont accessibles par index avec std::get<INDEX>(Tuple_object)

Dans le corps de la boucle for, vous pouvez facilement créer un alias sur les objets, même si vous devez toujours utiliser _.first_ ou _std::get_ pour la condition de boucle for et l'expression de mise à jour.

_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 et C++ 03 Vous pouvez nommer explicitement les types d'un _std::pair_. Il n'y a pas de moyen standard de généraliser ceci à plus de deux types:

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

Vous ne pouvez pas déclarer plusieurs types dans l'initialisation, mais vous pouvez affecter à plusieurs types E.G.

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

Il suffit de les déclarer dans leur propre champ.

14
zmbush

Voir " Y a-t-il un moyen de définir des variables de deux types dans une boucle for?? " pour une autre façon impliquant l'imbrication de plusieurs boucles for. L’avantage de l’autre solution par rapport à la "struct astuce" de Georg est qu’elle (1) vous permet d’avoir un mélange de variables locales statiques et non statiques et (2) d’avoir des variables non-copiables. L'inconvénient est qu'il est beaucoup moins lisible et peut être moins efficace.

1
tgoodhart

Je pense que la meilleure approche est réponse de xian .

mais...


# Imbriqué pour la boucle

Cette approche est sale, mais peut résoudre du tout version.

alors, je l’utilise souvent dans des fonctions macro.

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
    }

Supplémentaire 1.

Il peut également être utilisé pour declare local variables et 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.
    }

Supplémentaire 2.

Bon exemple: avec fonction macro.

(Si meilleure approche ne peut pas être utilisé car il s'agit d'une macro for-loop)

#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
    }

# Astuce de déclaration

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

Si vous voulez initialiser avec 0 ou nullptr, vous pouvez utiliser cette astuce.

mais je ne le recommande pas à cause d'une lecture difficile.

et cela ressemble à un bug.

0
mgcation

Définir une macro:

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

Rappelez-vous simplement que vos portées variables ne seront pas dans la boucle for de cette façon non plus.

0
Ryan Favale