2013-02-27 14 views
15

Quando trasformo il codice da C a C++, talvolta mi imbatto in costrutti di linguaggio C, ma compatibili con C++. Di solito voglio trasformare il codice nel modo meno intrusivo. Ma ho un caso in cui trovo che molto difficile:C++: equivalente agli array inizializzati in modo incompleto in C?

In C si può dichiarare un array e inizializzazione ... beh ... parti di esso utilizzando "designatori", il resto è azzerato (Edit: ho scritto "lasciato alla casualità" qui, in primo luogo):

int data[7] = { 
    [2] = 7, 
    [4] = 9, 
}; 

Questo non è valido C++ - codice, anche se (per fortuna). Quindi dovrò usare una strategia diversa.

Mentre posso vedere un modo non intrusivo in C++ 11:

static const map<int,int> data = { {2,7}, {4,9} }; 

cosa devo fare quando C++ 11-caratteristiche non sono ancora disponibili?

  • È possibile aggirare l'inizializzazione del runtime ?
  • C'è un modo per inizializzare un tipo simile di mappatura in modo "letterale"?
  • Che cos'è meno intrusivo per il codice che utilizza data?
+0

Quindi hai intenzione di usare solo gli indici '2' e' 4', o hai ancora bisogno degli altri indici? –

+0

Di solito questi sono mappaggi "statici cost", mappando i valori di enumerazione alle stringhe leggibili dall'uomo. Non vengono modificati in alcun modo in fase di esecuzione. – towi

+0

Intendevi "pedante"? o 'dependant'? –

risposta

6

Se l'inizializzazione uniforme non è disponibile, il std::map<int, int> poteva essere inizializzato utilizzando boost::assign::map_list_of:

#include <boost/assign/list_of.hpp> 
static const std::map<int,int> data = boost::assign::map_list_of(2,7)(4,9); 
+0

Buona soluzione. Non ero a conoscenza di quella funzione di * boost *. Ma introdurre la spinta in un progetto è un bel boccone che si può considerare solo "non intrusivo" con alcune definizioni di "intrusivo". Userò questo quando * boost * è già nel progetto, mi chiedo se c'è anche un modo senza boost? – towi

+0

Non c'è modo senza librerie di terze parti. Tranne il modo di scrivere il tuo :) – ixSci

1

Perché non si può fare:

int data[7]; 
data[2] = 7; 
data[4] = 9; 

sembra molto-molto simile =)

+0

Questo è runtime e questa è una delle mie opzioni attuali, sì. Ahimè, il codice potrebbe trovarsi in una libreria che porto. E l'inizializzazione deve quindi essere eseguita in una funzione che è garantita per essere chiamata, cioè all'inizializzazione della libreria. Alcune librerie non hanno questa funzione, quindi non puoi essere sicuro che ogni codice client sta inizializzando correttamente la mappa. – towi

11

Beh, a meno che la dimensione dell'array non sia completamente pazzesca, puoi sempre farlo

int data[7] = { 
    0, 
    0, 
    7, // #2 
    0, 
    9 // #4 
    // the rest will be 0-initialized 
}; 

Lavori in fase di compilazione troppo

+0

Buona idea, si. In effetti, penso di aver incontrato quella dimensione insana. Ma comunque, potrei generare quel codice sorgente. Hmmmm .... si mi piace. – towi

+0

Questo è senza dubbio il metodo che è "meno intrusivo del codice che usa' dati' ". –

1

Se non si desidera utilizzare boost::assign È possibile creare è semplice analogico:

template<class T1, class T2> 
std::map<T1, T2> cre(std::map<T1, T2> & m) 
{ 
    return std::map<T1, T2>(); 
} 

template<class T1, class T2> 
std::map<T1, T2> & ass(std::map<T1, T2> & m, T1 const & p1, T2 const & p2) 
{ 
    m[p1] = p2; 
    return m; 
} 

std::map<int, int> data = ass(ass(cre(data), 2, 3), 7, 6); 
+0

Tu e @ecatmur avete scelto la stessa soluzione. Ok. – towi

3

Invece di utilizzare map<int, int> è possibile backport std:array (o un equivalente minimo) da C++ 11 e utilizzare un costruttore Boost.Assign:

#include <cstddef> 

template<typename T, size_t N> struct array { T data[N]; }; 
template<typename T, size_t N> struct build_array: public array<T, N> { 
    build_array &operator()(size_t i, const T &t) { 
     this->data[i] = t; 
     return *this; 
    } 
}; 

array<int, 7> data_array = build_array<int, 7>()(2, 7)(4, 9); 
int (&data)[7] = data_array.data; 
+1

In un certo senso, sì. La mia unica preoccupazione è che ovviamente è anche l'inizializzazione del runtime. Immagino che il corpo di '()' sia troppo complesso per un compilatore da srotolare in fase di compilazione (non sarebbe 'constexpr' in C++ 11). Ma il tuo esempio mi porta alla possibilità di inizializzare 'data' con una funzione' int * initData() '- ignorando" perdite di memoria ". – towi