2013-04-28 37 views
5

Tôi đã tình trạng này:Có một cú pháp cụ thể để khởi tạo một mảng std :: từ một mảng khác, std :: khác nhau không?

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

Có, bởi bất kỳ cơ hội, một cú pháp tốt hơn thế này để tránh gõ tất cả các yếu tố xuống? (Và điều đó sẽ không yêu cầu can thiệp vào cơ hội mà some_constant_value sẽ thay đổi?)

+0

Bạn có cần * khởi tạo hoặc bạn có thể thực hiện tuyến đường dễ dàng và thực hiện chuyển nhượng không? – Pubby

+0

@Pubby Tôi không thể thực hiện nhiệm vụ vì B sẽ không xây dựng mà không có đối số, thật không may. – Svalorzen

Trả lời

4

Tôi có mã này nằm xung quanh. Tôi nghĩ rằng đó là những gì bạn muốn:

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

Sau đó, bạn có thể làm:

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

Hút thuốc lá, nó hoạt động! Ngay sau khi tôi hiểu toàn bộ điều tôi sẽ chấp nhận điều này như một câu trả lời, cảm ơn. – Svalorzen

+0

@Svalorzen Xin lỗi vì thiếu giải thích. Nếu bạn cần giúp đỡ hiểu một số phần thì chỉ cần hỏi. – Pubby

+0

Bạn có thể giảm bớt một chút bằng cách loại bỏ khai báo phía trước vô dụng của array_convert, loại bỏ các diễn viên rõ ràng để To (OP đang làm ngầm) và sử dụng 'tự động' trong ví dụ. Một vài từ ít nên mất một vài giây ít hơn để hiểu ;-) –

1

Một giải pháp thay thế được cung cấp bởi bộ thư viện chuẩn là:

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

Lưu ý rằng đối số của các nhà xây dựng được đính kèm bởi ((...)), sao cho nó được phân tích cú pháp chính xác dưới dạng biểu thức dấu phẩy thay vì hai đối số.

Giải pháp này dựa trên thực tế là B được xây dựng hoàn toàn từ A. Một giải pháp ngắn đó cũng sẽ có tác dụng nếu các nhà xây dựng chuyển đổi được làm rõ là:

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

Các chương trình thử nghiệm sau đây, được xây dựng với GCC 4.7.2, Clang 3.2 và Intel C++ 13.1.1, (tùy chọn -g -O0 -Wall -std=c++11) minh họa cả hai giải pháp:

#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; 
} 
Các vấn đề liên quan