La raison pour laquelle cela ne fonctionne pas est que les éléments sous-jacents de la std::initializer_list
sont copiés à partir de a
y b
et sont de type const Obj
Vous essayez donc essentiellement de lier une valeur constante à une référence mutable.
On peut essayer de résoudre ce problème en utilisant :
for (auto obj : {a, b}) {
obj.i = 123;
}
mais on s'apercevrait vite que les valeurs réelles de i
dans les objets a
y b
n'a pas changé. La raison en est que lorsque l'on utilise auto
ici, le type de la variable de la boucle obj
deviendra Obj
donc vous ne faites que boucler sur des copies de a
y b
.
La façon dont cela devrait être corrigé est que vous pouvez utiliser std::ref
(défini dans le <functional>
), pour que les éléments de la liste des initialisateurs soient de type std::reference_wrapper<Obj>
. Ce qui est implicitement convertible en Obj&
Vous pouvez donc le garder comme type de la variable de la boucle :
#include <functional>
#include <initializer_list>
#include <iostream>
struct Obj {
int i;
};
Obj a, b;
int main()
{
for (Obj& obj : {std::ref(a), std::ref(b)}) {
obj.i = 123;
}
std::cout << a.i << '\n';
std::cout << b.i << '\n';
}
Sortie :
123
123
Une autre façon de procéder serait de faire en sorte que la boucle utilise const auto&
y std::reference_wrapper<T>::get
. Nous pouvons utiliser une référence constante ici, parce que le reference_wrapper
n'est pas modifié, seule la valeur qu'il enveloppe l'est :
for (const auto& obj : {std::ref(a), std::ref(b)}) {
obj.get().i = 123;
}
mais je pense que, parce que l'utilisation auto
force ici l'utilisation de .get()
Cette méthode est assez lourde et il est préférable d'utiliser la première méthode pour résoudre ce problème.
Il pourrait sembler plus simple de faire cela en utilisant des pointeurs bruts dans la boucle comme @francesco l'a fait dans sa réponse, mais j'ai l'habitude d'éviter les pointeurs bruts autant que possible, et dans ce cas, je crois simplement que l'utilisation de références rend le code plus clair et plus propre.