Lo siguiente no compila:
#include <iostream>
int main()
{
int a{},b{},c{},d{};
for (auto& s : {a, b, c, d}) {
s = 1;
}
std::cout << a << std::endl;
return 0;
}
El error del compilador es: error: assignment of read-only reference 's'
Ahora, en mi caso real, la lista está hecha de variables miembro en una clase.
Ahora, esto no funciona porque la expresión se convierte en una initializer_list<int>
que realmente copia a, b, c y d, por lo tanto, tampoco permite modificaciones.
Mi pregunta es doble:
¿Hay alguna motivación detrás de no permitir escribir un bucle for basado en rango de esta manera? p.ej. tal vez podría haber un caso especial para las expresiones con llaves desnudas.
¿Cuál es una forma ordenada sintáctica de arreglar este tipo de bucle?
Algo en esta línea sería preferible:
for (auto& s : something(a, b, c, d)) {
s = 1;
}
No considero que la indirección del puntero sea una buena solución (es decir {&a, &b, &c, &d}
): cualquier solución debe dar referencia al elemento directamente cuando se des-referencia el iterador .
fuente
{ &a, &b, &c, &d }
.initializer_list
es principalmente una vista enconst
matriz.{ &a, &b, &c, &d }
, tampoco querrás:for (auto& s : std::initializer_list<std::reference_wrapper<int>>{a, b, c, d}) { s.get() = 1; }
Respuestas:
Los rangos no son tan mágicos como a la gente le gustaría. Al final, debe haber un objeto que el compilador pueda generar llamadas a una función miembro o una función libre
begin()
yend()
.Lo más probable que puedas venir es:
fuente
std::vector<int*>
.auto s
oauto* s
noauto& s
.Solo otra solución dentro de una idea envolvente:
Entonces:
salidas
fuente
De acuerdo con el estándar §11.6.4 List-initialization / p5 [dcl.init.list] [ Emphasis Mine ]:
Por lo tanto, su compilador se queja legítimamente (es decir,
auto &s
deduceint const& s
y no puede asignarlos
en el bucle a distancia).Puede aliviar este problema introduciendo un contenedor en lugar de una lista de inicializador (por ejemplo, `std :: vector ') con' std :: reference_wrapper ':
Demo en vivo
fuente
for (auto& s : {a, b, c, d})
no funciona. En cuanto a por qué el estándar tiene esa cláusula ..... tendrías que preguntar a los miembros del comité de estandarización. Al igual que muchas de estas cosas, el razonamiento podría ser cualquier cosa entre "No consideramos que su caso en particular fuera lo suficientemente útil como para preocuparse por" hasta "Demasiadas otras partes del estándar tendrían que cambiar para respaldar su caso, y pospusimos la consideración de todo eso hasta que desarrollemos un estándar futuro ".std::array<std::reference_wrapper>>
?Para satisfacer esa sintaxis
podrías crear un contenedor:
Manifestación
fuente
std::reference_wrapper
?std::reference_wrapper
requerirías.get() = 1;
.Solución: use un contenedor de referencia
Luego se usa como:
Sin embargo, esto no intenta responder a la primera pregunta.
fuente
Puede crear una clase de contenedor para almacenar referencias y que tendrá un operador de asignación para actualizar este valor:
Demo en vivo
fuente