2012-02-07 18 views
6

quisiera realizar la misma operación en varias matrices, algo así como:¿Iteración sobre referencias?

#include<vector> 
#include<algorithm> 
int main(void){ 
    std::vector<double> a, b; 
    for(auto& ab:{a,b}) std::sort(ab.begin(),ab.end()); // error 
} 

Este código de falla, ya auto& es una constante referencia. ¿Hay una forma elegante de evitarlo?

+1

¿Cuál es '{a, b}'? –

+2

@Lightness es un 'std :: initializer_list >'. El problema aquí es que los iteradores de una lista de inicializadores son * siempre * 'const'. –

+0

Así que ahí lo tienes. Me pregunto si alguna magia de reenvío podría ayudar aquí. –

Respuesta

7

Creo que el problema es que es un poco como vincular una referencia temporal a una referencia no constante. No hay una colección "concreta" allí, así que es un poco temporal.

SI tiene un vector temporal allí, se vinculará a una referencia constante pero no a una constante.

también creo que esto no volverá a trabajar lo que está haciendo, pero esto debería funcionar:

#include<vector> 
#include<algorithm> 
int main(void) 
{  
    std::vector<double> a, b;  
    for(std::vector<double>* ab:{&a,&b}) 
     std::sort(ab->begin(),ab->end()); // or begin(*ab),end(*ab) 
} 

y concesionarios puede trabajar también.

+0

Oh sí, los indicadores lo resuelven de una manera elegante, gracias.Y uno puede escribir tanto 'auto' como' auto * ':-) – eudoxos

+3

mi sensación inmediata de lo que estabas haciendo era que incluso si lo compilabas, estarías ordenando copias de manera efectiva. Es por eso que tienes suerte de una manera que el compilador te detuvo. – CashCow

+0

@CashCow: Correcto, 'std :: initializer_list' se copia automáticamente. – Xeo

2

Este código falla, desde auto & es una referencia constante. [énfasis mío]

Su razonamiento no se sostiene. En un bucle for basado en rango, lo que usted declara (aquí, auto& ab) es no vinculado a la expresión de rango (aquí, {a,b }). En su lugar, ab se inicializará a partir del elementos del rango, no el rango en sí.

En su lugar, el error proviene de llamar a std::sort con los parámetros ab.begin()/ab.end(), que pueden ser fácilmente observados al comentar el cuerpo del bucle. Como ha señalado RMartinho, los elementos del std::initializer_list<std::vector<double>> son inmutables, y no se puede ordenar un contenedor const (std::sort mezcla los elementos usando movimientos, no se puede asignar a un elemento const).

Suponiendo que desee (de forma independiente) Clasificar los dos vectores, se puede hacer:

for(auto& ab: { std::ref(a), std::ref(b) }) 
    std::sort(std::begin(ab.get()), std::end(ab.get())); 

en cuenta que de acuerdo a las reglas de deducción de argumento plantilla, auto& está muy bien aquí y auto se deducirá a const std::reference_wrapper<std::vector<double>>, produciendo std::reference_wrapper<std::vector<double>> const& como el tipo de ab.

+0

Estaba pensando lo mismo: no puede tener un vector de referencias porque carece de la semántica, pero una lista de inicialización de std :: ref podría funcionar bien, en cuyo caso no tendría que desreferenciar los punteros como yo hizo. No estoy seguro de que necesite auto &, el auto podría funcionar bien ya que get() es un miembro constante de un estándar :: ref. De la misma manera que la mina funciona, ya que tengo punteros const pero no punteros para const. – CashCow

+0

¿Es esta una característica especial de std :: ref? ¿Por qué no se deduce automáticamente a const std :: ref_t > & en el que se puede llamar a std :: vector & get() const – CashCow

+0

@CashCow Mi error, 'std :: vector ' doesn ' Tengo un miembro 'get' y realmente quería referirme a' std :: reference_wrapper > '. Gracias por el aviso. –

0

Creo que la solución CashCows es agradable. Solo para mostrar una forma diferente: también puedes usar plantillas variadic para resolver esto.

#include <vector> 
#include <algorithm> 

using namespace std; 

void mysort() {} // termination version 

template<typename Arg1, typename... Args> 
void mysort(Arg1 &arg1, Args&... args) 
{ 
    sort(arg1.begin(), arg1.end()); 
    mysort(args...); 
} 

int main(void) 
{ 
    vector<double> a, b; 
    mysort(a, b); 
} 

@CashCow: Es posible pasar un algoritmo como argumento, pero es un poco feo debido a la utilización de decltype:

#include <vector> 
#include <algorithm> 

using namespace std; 

template<typename Algo> 
void mysort(Algo algo) {} // termination version 

template<typename Algo, typename Arg1, typename... Args> 
void mysort(Algo algo, Arg1 &arg1, Args&... args) 
{ 
    algo(arg1.begin(), arg1.end()); 
    mysort(algo, args...); 
} 

int main(void) 
{ 
    vector<double> a, b; 
    mysort(&sort<decltype(a.begin())>, a, b); 
} 
+0

Bien, pero podemos agregar una lambda a su plantilla variadic que nos permite poner en el algoritmo que queremos llamar, es decir, modificar la clasificación a cualquier algoritmo que tome un rango. Por cierto, ¿ahora no se ordena el trabajo en un rango sin tener que especificar el ser y el final? Algoritmos automáticamente lo llamará por ti. No pude hacer eso en mi solución porque tomó punteros. – CashCow

+0

@CashCow ver mi edición para una versión que toma un algoritmo como parámetro. – frast

Cuestiones relacionadas