2012-02-07 6 views
6

Vorrei per eseguire la stessa operazione su più array, qualcosa di simile:Iterazione sui riferimenti?

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

Questo codice non funziona, dal momento che è un auto& const riferimento. C'è un modo elegante attorno ad esso?

+1

Qual è '{a, b}'? –

+2

@Lightness è un 'std :: initializer_list >'. il problema qui è che gli iteratori di un elenco di inizializzazione sono * sempre * 'const'. –

+0

Quindi eccoci. Mi chiedo se qualche ralue forwarding magic possa aiutare qui. –

risposta

7

Penso che il problema sia un po 'come legare un riferimento temporaneo a un non-const. Non esiste una collezione "concreta", quindi è un po 'temporanea.

Se si dispone di un vettore temporaneo, esso si collegherà a un riferimento const ma non a uno const-const.

Penso anche che questo non funzionerà mai quello che stai facendo, ma questo dovrebbe funzionare:

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

e auto può funzionare anche.

+0

Oh sì i puntatori risolvono in modo elegante, grazie.E uno può scrivere sia 'auto' che' auto * ':-) – eudoxos

+3

la mia sensazione immediata di ciò che stavi facendo era che anche se lo avessi compilato, dovresti effettivamente ordinare le copie. Ecco perché sei fortunato in un modo in cui il compilatore ti ha fermato. – CashCow

+0

@CashCow: corretto, 'std :: initializer_list' copia automaticamente. – Xeo

2

Questo codice non funziona, poiché l'auto & è un riferimento const. [emphasis mine]

Il tuo ragionamento non regge. In un ciclo for-range, ciò che dichiari (qui, auto& ab) è non associato all'espressione di intervallo (qui, {a,b }). Invece, ab verrà inizializzato dagli elementi dell'intervallo, non dall'intervallo stesso.

Invece l'errore deriva dal chiamare std::sort con i parametri ab.begin()/ab.end(), che può essere facilmente osservato commentando il corpo del ciclo. Come sottolineato da RMartinho, gli elementi di std::initializer_list<std::vector<double>> non sono modificabili e non è possibile ordinare un contenitore const (elementi std::sort utilizzando le mosse, non è possibile assegnare a un elemento const).

Supponendo che si desidera (in modo indipendente) ordinare entrambi i vettori, si può fare:

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

Si noti che in base alle leggi di deduzione modello di argomento, auto& va bene qui e auto sarà dedotta al const std::reference_wrapper<std::vector<double>>, cedendo std::reference_wrapper<std::vector<double>> const& come il tipo di ab.

+0

Stavo pensando la stessa cosa: non si può avere un vettore di riferimenti perché manca la semantica, ma una lista di inizializzazione di std :: ref potrebbe funzionare bene, nel qual caso non è necessario dereferenziare i puntatori come I fatto. Non sono sicuro che tu abbia bisogno di auto e, auto potrebbe andare bene dato che get() è un membro const di uno std :: ref. Lo stesso modo in cui il mio funziona in quanto ho puntatori const, ma non puntatori a const. – CashCow

+0

È una caratteristica speciale di std :: ref? Perché non viene dedotto automaticamente da const std :: ref_t > & su cui puoi chiamare std :: vector & get() const – CashCow

+0

@CashCow Errore mio, 'std :: vector ' doesn ' Ho un membro 'get' e volevo davvero fare riferimento a' std :: reference_wrapper > '. Grazie per il testa a testa. –

0

Penso che la soluzione CashCows sia buona. Solo per mostrare un modo diverso: potresti anche usare modelli variadici per risolvere questo problema.

#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: E 'possibile passare un algoritmo come argomento, ma è un po' brutto a causa dell'uso di 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

Bello, ma possiamo aggiungere un lambda al modello variadic che ci consente di inserire l'algoritmo che vogliamo chiamare, cioè modificare l'ordinamento con qualsiasi algoritmo che prende un intervallo. Per inciso, non ordina ora il lavoro su un intervallo senza dover specificare l'essere e la fine? Algoritmi lo chiameranno automaticamente per te. Non potevo farlo nella mia soluzione perché ci sono voluti dei suggerimenti. – CashCow

+0

@CashCow vedi la mia modifica per una versione che accetta un algoritmo come parametro. – frast