2013-04-28 18 views
5

ho questa situazione:Esiste una sintassi particolare per inizializzare un array std :: da un altro std :: array diverso?

class A { 
    ... 
}; 

class B { 
    public: 
     B(A x) { .... } 
} 

std::array<A, some_constant_value> init; 
std::array<B, some_constant_value> arr = { 
    init[0], 
    init[1], 
    init[2], 
    ...... , 
    init[some_constant_value-1] 
}; 

è lì, per caso, una sintassi migliore di questo per evitare di digitare tutti gli elementi verso il basso? (E questo non richiederà l'ingerenza nella possibilità che qualche_constant_value cambierà?)

+0

Avete * bisogno * di inizializzazione o potete prendere la strada facile e fare un incarico? – Pubby

+0

@Pubby Non posso eseguire il compito perché B non costruirà senza argomento, sfortunatamente. – Svalorzen

risposta

4

Ho questo codice in giro. Penso che sia quello che vuoi:

template<unsigned... Indices> 
    struct indices { 
    using next = indices<Indices..., sizeof...(Indices)>; 
    }; 

    template<unsigned N> 
    struct build_indices { 
    using type = typename build_indices<N-1>::type::next; 
    }; 
    template<> 
    struct build_indices<0> { 
    using type = indices<>; 
    }; 

    namespace impl { 
    template<typename To, typename From, unsigned... Is> 
    std::array<To, sizeof...(Is)> 
    array_convert_impl(std::array<From, sizeof...(Is)> const& from, indices<Is...>) { 
     return std::array<To, sizeof...(Is)>{{ from[Is]... }}; 
    } 
    } // namespace impl 
    template<typename To, typename From, unsigned N> 
    std::array<To, N> 
    array_convert(std::array<From, N> const& from) { 
    return impl::array_convert_impl<To>(from, typename build_indices<N>::type()); 
    } 

allora si può fare:

std::array<B, some_constant_value> arr = array_convert<B>(init); 
+0

Holy smokes, funziona! Non appena avrò compreso l'intera cosa, accetterò questa risposta come risposta, grazie. – Svalorzen

+0

@Svalorzen Ci scusiamo per la mancanza di spiegazioni. Se hai bisogno di aiuto per capire una parte, basta chiedere. – Pubby

+0

È possibile ridurlo un po 'rimuovendo la dichiarazione forward inutile di array_convert, rimuovendo il cast esplicito su To (l'OP sta facendo implicito) e usando 'auto' nell'esempio. Qualche parola in meno dovrebbe richiedere qualche secondo in meno ;-) –

1

Una soluzione alternativa fornita dalla libreria standard è:

std::array<B, some_constant_value> 
arr((std::copy(init.begin(),init.end(),(&arr)->begin()),arr)); 

Nota che l'argomento del costruttore è racchiuso da ((...)), in modo che esso venga analizzato correttamente come espressione di virgola anziché come due argomenti.

Questa soluzione si basa sul fatto che B è implicitamente costruibile da A. Una breve soluzione che funziona anche se il costruttore di conversione è reso esplicito è:

auto lamb = 
[&init]() -> B { static size_t i = 0; return B(init[i++]); }; 
std::array<B, some_constant_value> 
arr((std::generate((&arr)->begin(),(&arr)->end(),lamb),arr)); 

Il seguente programma di test, costruita con GCC 4.7.2, clang 3.2 e Intel C++ 13.1.1, (opzioni -g -O0 -Wall -std=c++11) illustra entrambe le soluzioni:

#include <iostream> 
#include <array> 
#include <algorithm> 

struct A 
{ 
    int _i = 42; 
}; 

struct B 
{ 
    B(A x) 
    : _i(x._i){} 
    int _i; 
}; 

struct C 
{ 
    explicit C(A x) 
    : _i(x._i){} 
    int _i; 
}; 

using namespace std; 

int main() 
{ 
    array<A, 10> init; 
    array<B, 10> arr((copy(init.begin(),init.end(),(&arr)->begin()),arr)); 
    cout << "arr contains..." << endl; 
    for (size_t i = 0; i < arr.size(); ++i) { 
     cout << arr[i]._i << endl; 
    } 
    auto lamb = 
    [&init]() -> C { static size_t i = 0; return C(init[i++]); }; 
    array<C, 10> brr((generate((&brr)->begin(),(&brr)->end(),lamb),brr)); 
    cout << "brr contains..." << endl; 
    for (size_t i = 0; i < brr.size(); ++i) { 
     cout << brr[i]._i << endl; 
    } 
    return 0; 
} 
Problemi correlati