2015-12-09 22 views
6

Tôi muốn tạo một mảng 2D được điền bởi một số hàm đã biết với không có thời gian chạy trên.Khởi tạo mảng 2D đơn giản với một hàm nhất định trên thời gian biên dịch

Để có ví dụ, giả sử một hàm f(x, y) = 10 * y + x, hãy để x ở trong {1, 2, 3}y trong {4, 5, 6}. Tôi muốn tạo mảng 2D có nội dung

41 42 43 
51 52 53 
61 62 63 

Bây giờ, cách dễ nhất để thực hiện là chỉ mã hóa trực tiếp các giá trị trong nguồn của tôi. Và nó thực sự là thích hợp cho công việc của tôi, vì vậy câu hỏi là chỉ ra khỏi tò mò.

Tôi muốn tạo một metafunc và một cấu trúc sở hữu một loại ma thuật đen, cho phép tôi xác định một mảng trong số các giá trị đã cho cho xy. Như thế này:

template<int X> struct Func { 
    template<int Y> struct over { 
    static const int value = 10 * Y + X; // f(x, y) 
    }; 
}; 

template<int... args1> struct Rows { 
    template<int... args2> struct Cols { 
    static const int data[sizeof...(args1)][sizeof...(args2)]; 
    }; 
}; 

template<int... args1> 
template<int... args2> 
const int Rows<args1...>::Cols<args2...>::data[sizeof...(args1)][sizeof...(args2)] = { 
    { Func<args1>::over<args2>::value... } // This does not do what I want :(
              // Need some black magic here 
}; 

// Here is my precious table 
const auto& table = Rows<1, 2, 3>::Cols<4, 5, 6>::data; 

Nếu tôi in các giá trị từ bảng, tôi có điều này:

41 52 63 
0 0 0 
0 0 0 

tôi hiểu những gì đang xảy ra, thuật ngữ Func<args1>::over<args2>::value có hai gói thông số trong đó, args1args2, vì vậy việc áp dụng ... đồng thời mở rộng chúng đồng thời và tôi chỉ có 3 thành viên thay vì 9.

Nếu bạn đã đạt đến thời điểm này, bạn đã hiểu những gì tôi muốn. Vì vậy, câu hỏi là, làm thế nào để tôi làm điều đó? Làm thế nào để áp dụng dấu ba chấm riêng biệt cho cả hai gói tham số vì vậy tôi có thể có sự kết hợp Descartes trong initializer? Hoặc có thể có một số cách khác để làm điều đó?

Tôi biết về this answerthat answer. Chúng sử dụng std::array thay cho mảng đồng bằng, vì vậy chúng đầu tiên xây dựng mảng 1D, và sau đó khởi tạo mảng 2D với một số mảng 1D. Nhưng nếu tôi hiểu chính xác, việc khởi tạo này phải được thực hiện trong thời gian chạy. Tôi muốn tránh điều đó. Tuy nhiên, tôi không phản đối std::array. Tôi cho rằng với một trình biên dịch thích hợp, chúng cũng nhanh như các mảng đơn giản.

Nhân tiện, đây là số possible solution của tôi bằng cách sử dụng tổng quát constexpr từ C++ 14 và câu hỏi về nó. Bất kỳ ý tưởng về cách giải quyết nhiệm vụ với constexpr từ C++ 11 cũng được hoan nghênh.

+0

Lặp lại hàng trước, sau đó lặp qua các cột. – VermillionAzure

+0

Tôi hoàn toàn kinh khủng, nhưng cách nó được viết ngay bây giờ là "mơ hồ". Cấu trúc được lồng nhau, nhưng nó không có lặp lại mẫu lồng nhau. Vì vậy, có thể thử có loại được chỉ định cho cấu trúc cấp cao nhất và sau đó tạo một loại khác với mức thứ hai nghiêm ngặt vẫn còn với danh sách variadic. Sau đó, khởi tạo một trường hợp cụ thể với trường hợp khởi tạo cấp cao nhất. – VermillionAzure

+0

Bạn có thực sự cần một mảng 2d không?Bạn chỉ tìm thấy giải pháp cho mảng 1d –

Trả lời

1

Cách duy nhất tôi thấy nó là để tách các gói thông số bằng dấu phẩy và mở rộng một trong số họ, và sau đó mở rộng khác từ bên ngoài:

#include <array> 
#include <utility> 

using namespace std; 

template<class T, T Y, T... Xs> 
constexpr array<T, sizeof...(Xs)> a1{10*Y+Xs...}; 

template<class T, T... Xs, T... Ys> 
constexpr auto a2(integer_sequence<T, Xs...>, integer_sequence<T, Ys...>) { 
    return array<array<T, sizeof...(Xs)>, sizeof...(Ys)>{a1<T, Ys, Xs...>...}; 
} 

array<array<int, 3>, 3> table(a2(
    integer_sequence<int, 1, 2, 3>(), 
    integer_sequence<int, 4, 5, 6>() 
)); 

Kết quả asm là thế này:

table: 
     .long 41 
     .long 42 
     .long 43 
     .long 51 
     .long 52 
     .long 53 
     .long 61 
     .long 62 
     .long 63 

Code in Compiler Explorer

+0

Cảm ơn câu trả lời, nhưng nó chỉ hoạt động trong C++ 14, không phải trong C++ 11, trong khi tôi đã có một giải pháp cho C++ 14. – Mikhail

Các vấn đề liên quan