2014-09-27 2 views
8

Quando si tratta di un vettore const, il seguente non funziona:Qual è l'equivalente di boost :: make_transform_iterator nella libreria standard?

const std::vector<std::string> v; 
v.push_back("test"); // error: v cannot be modified 

Invece, è necessario inizializzare il vettore sulla stessa linea in cui è costruito. Tuttavia, anche con questa limitazione, boost::make_transform_iterator rende facile fare qualcosa con gli elementi di un altro vettore prima di loro spingendo in v In questo esempio, convert è una funzione unaria che restituisce una versione trasformata di un elemento di input:.

auto beg = boost::make_transform_iterator(args.begin(), convert); 
auto end = boost::make_transform_iterator(args.end(), convert); 

const std::vector<const char*> vc { beg, end }; 

Ho dato un'occhiata alle funzioni disponibili in <iterator> e non vedo un equivalente. Manca semplicemente o c'è una ragione per cui la libreria standard non ce l'ha?

+3

Se ci fosse un equivalente, sarebbe più probabile essere chiamato 'std :: make_transform_iterator'. Non ce n'è uno. Ci sono molte cose utili in boost (e in altre librerie) che non sono nella libreria standard. –

+0

Non è ovvio quello che stai cercando di fare. Forse 'const std :: vector v = {" ciao "," mondo "};'? –

+0

@Marc No, voglio che 'vc' non venga modificato perché verrà popolato da' c_str() ', che ho letto può portare a puntatori invalidati se' vc' ridimensiona o qualcosa del genere. Quindi sto provando a inizializzarlo su una riga rispetto a dover usare std :: transform su una seconda riga. – user4085715

risposta

3

per C++ 11 c'è sempre la lambda di inizializzazione inplace trucco:

const auto vc = [&]{ 
    std::vector<const char*> tmp(v.size()); 
    std::transform(v.begin(), v.end(), tmp.begin(), convert); 
    return tmp; 
}(); 

o

const auto vc = [&]{ 
    std::vector<const char*> tmp; 
    tmp.reserve(v.size()); 
    std::transform(v.begin(), v.end(), back_inserter(tmp), convert); 
    return tmp; 
}(); 

Guardalo Live On Coliru

che è detto, preferirei gli adattatori Boost Range: (anche Live On Coliru)

const auto vc = boost::copy_range<std::vector<const char*> >(v | transformed(convert)); 
#include <algorithm> 
#include <vector> 
#include <iterator> 
#include <string> 

#include <functional> 
#include <iostream> 

int main() 
{ 
    const std::vector</* const */ std::string> v { "test", "goodbye" }; 

    auto convert = std::mem_fn(&std::string::c_str); 

    const auto vc = [&]{ 
     std::vector<const char*> tmp; 
     tmp.reserve(v.size()); 
     std::transform(v.begin(), v.end(), back_inserter(tmp), convert); 
     return tmp; 
    }(); 

    for (auto cc : vc) 
     std::cout << cc << "\n"; 
} 
+0

Credo che la linea di codice che inizia '' 'const auto vc = boost :: copy_range ...' '' non ha alcuna relazione con il blocco di codice che inizia con le istruzioni '' '# include''', e che i due sono pensati per essere approcci separati, in cui preferisci il primo. È corretto? – Alan

+0

@Alan corretto. Gli adattatori Boost Range consentono di dire praticamente la stessa cosa in una riga – sehe

+0

Ho modificato la risposta di conseguenza. Grazie. – Alan