2013-04-28 2 views
5

Ich habe diese Situation:Gibt es eine bestimmte Syntax für die Initialisierung eines std :: -Array von einem anderen, anderen 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] 
}; 

Gibt es durch Zufall, eine bessere Syntax als diese nach unten, alle Elemente zu vermeiden eingeben? (Und das erfordert keine Einmischung in den Fall, dass some_constant_value wird sich ändern?)

+0

Benötigen Sie * Initialisierung * oder können Sie die einfache Route nehmen und Aufgabe übernehmen? – Pubby

+0

@Pubby Ich kann die Zuweisung nicht machen, weil B leider ohne Argument nicht konstruiert wird. – Svalorzen

Antwort

4

Ich habe diesen Code herumliegen. Ich denke, es ist das, was Sie wollen:

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

Dann können Sie tun:

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

Heilige raucht, es funktioniert! Sobald ich das Ganze verstanden habe, werde ich das als Antwort akzeptieren, danke. – Svalorzen

+0

@Svalorzen Entschuldigung für den Mangel an Erklärung. Wenn Sie Hilfe benötigen, um ein Teil zu verstehen, dann fragen Sie einfach. – Pubby

+0

Sie können es ein wenig reduzieren, indem Sie die unbrauchbare Forward-Deklaration von array_convert entfernen, die explizite Umwandlung in To (OP macht implizit) und im Beispiel "auto" entfernen. Ein paar Worte weniger sollten ein paar Sekunden weniger brauchen, um zu verstehen ;-) –

1

Eine alternative Lösung der Standardbibliothek zur Verfügung gestellt ist:

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

Beachten Sie, dass das Argument des Konstruktors wird von ((...)) eingeschlossen, so dass es korrekt als ein Komma-Ausdruck statt als zwei Argumente analysiert wird. Diese Lösung beruht auf der Tatsache, dass B implizit von A konstruierbar ist. Eine kurze Lösung, die auch funktioniert, wenn die Umwandlung Konstruktor explizit gemacht ist:

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

Das folgende Testprogramm, gebaut mit GCC 4.7.2, klirrte 3.2 und Intel C++ 13.1.1, (Optionen -g -O0 -Wall -std=c++11) stellt beide Lösungen dar:

#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; 
} 
Verwandte Themen