2013-04-28 14 views
5

Mam taką sytuację:Czy istnieje szczególna składnia do inicjowania std :: array z innej, innej std :: array?

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] 
}; 

jest tam, przypadkiem, składni lepszego niż to, aby uniknąć wpisywania wszystkich elementów w dół? (I to nie będzie wymagać wtrącania się w niecałkowitą szansę, że zmienna some_constant_value zmieni się?)

+0

Czy * potrzebujesz * inicjalizacji lub czy możesz wybrać łatwą trasę i wykonać zadanie? – Pubby

+0

@Pubby Nie mogę wykonać zadania, ponieważ B nie zbuduje bez argumentów, niestety. – Svalorzen

Odpowiedz

4

Mam ten kod leżący w pobliżu. Myślę, że to, co chcesz:

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()); 
    } 

Następnie można zrobić:

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

Holy smokees, to działa! Jak tylko zrozumiem całą rzecz, zaakceptuję to jako odpowiedź, dzięki. – Svalorzen

+0

@Svalorzen Przeprosiny za brak wyjaśnienia. Jeśli potrzebujesz pomocy w zrozumieniu części, po prostu zapytaj. – Pubby

+0

Możesz go nieco zredukować, usuwając bezużyteczną deklarację forward tablicy array_convert, usuwając jawny rzut do To (OP robi niejawnie) i używając 'auto' w tym przykładzie. Kilka słów mniej powinno zająć kilka sekund mniej, aby to zrozumieć ;-) –

1

Alternatywnym rozwiązaniem świadczone przez biblioteki standardowej jest:

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

Należy zauważyć, że argument konstruktora jest zamknięty przez ((...)), tak aby jego numer został poprawnie przeanalizowany jako przecinek, a nie jako dwa argumenty.

Rozwiązanie to polega na tym, że B jest domyślnie możliwe do skonstruowania z A. Krótki rozwiązanie, które będzie również działać, jeśli konstruktor konwersji jest wyraźnie jest:

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)); 

Poniższy program testowy, zbudowany z GCC 4.7.2, dzyń 3.2 i Intel C++ 13.1.1, (opcje -g -O0 -Wall -std=c++11) ilustruje oba rozwiązania:

#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; 
} 
Powiązane problemy