5

Khi tôi gọi: a7 [0] [1] [100];Toán tử [] Quá tải trong mảng đa chiều C++

Tôi có thể lấy chỉ mục đầu tiên '0' trong toán tử [] nhưng dưới dạng chỉ mục tôi sẽ không thể lấy các giá trị chỉ mục 1 và 100 khác theo cách đệ quy. Làm thế nào tôi có thể sử dụng toán tử [] để thu được các giá trị chỉ mục folowing đệ quy. Trong ví dụ này cho mảng 3 chiều, toán tử [] chỉ được gọi một lần cho thứ nguyên đầu tiên là '0'.

My Mã số Ví dụ:

template <class T, unsigned ... RestD> struct array; 

template <class T, unsigned PrimaryD> 
struct array <T, PrimaryD> { 
    typedef T type[PrimaryD]; 

    type data; 

    T& operator[] (unsigned i) { 
     return data[i]; 
    } 
}; 

template <class T, unsigned PrimaryD, unsigned ... RestD> 
struct array <T, PrimaryD, RestD...> { 
    typedef typename array<T, RestD...>::type OneDimensionDownArrayT; 
    typedef OneDimensionDownArrayT type[PrimaryD]; 

    type data; 

    OneDimensionDownArrayT& operator[] (int i) { 
     OneDimensionDownArrayT& a = data[i]; 
     return a; 
    } 
}; 

int main() { 

    array<int, 1, 2, 3> a7 {{{{1, 2, 3},{4, 5, 6}}}}; 
    a7[0][1][2] = 100; //=>won't recursively go through operator[] 
        //I want to recursively obtain 0, 1 and 2 as index values 

    a7[0][1][100] = 100; //also works correctly. 
    std::cout << a7[0][1][100] << std::endl; 

    return 0; 
} 
+0

Vậy vấn đề là gì? Bạn đang thấy hành vi gì? Nếu nó đưa ra một lỗi biên dịch, nó là gì? Hành vi thời gian chạy là gì? Trình biên dịch và phiên bản của bạn là gì? Một ít thông tin không đau, bạn biết đấy! – yzt

+3

Bạn đã xem xét ... không làm điều này? Chỉ cần sử dụng một 'operator()' overload thay thế. Thực sự, mọi người cố gắng * cách * quá khó để shoehorn 'operator []' thành các mảng đa chiều. –

+5

Một vài lưu ý phụ: [Tại sao giao diện lớp Matrix của tôi không giống mảng mảng?] (Http://www.parashift.com/c++-faq/matrix-array-of-array.html) và [Tôi vẫn không hiểu. Tại sao giao diện của lớp Matrix của tôi trông không giống mảng mảng?] (Http://www.parashift.com/c++-faq/matrix-c-style-subscript.html) –

Trả lời

1

Các lỗi ở đây thực sự là một chút tinh tế, thay đổi dòng

typedef typename array<T, RestD...>::type OneDimensionDownArrayT; 

để

typedef array<T, RestD...> OneDimensionDownArrayT; 

Lý do cho điều này là bởi vì array<int, 1, 2, 3>::type bình đẳng array<int, 2, 3>::type bằng array<int, 3>::typeint. Cuối cùng, bạn kết thúc với array<int, 1, 2, 3>::OneDimensionDownArrayT bằng int[2][3]. Đây là lý do tại sao bạn chỉ đi xuống một cấp trong toán tử quá tải của bạn [], bởi vì nó trả về một mảng ints thực tế. Bạn có thể tự mình xem nội dung này bằng cách thêm phương thức chính của mình:

 auto & e1 = a7[0]; 
     auto & e2 = e1[0]; 
     auto & e3 = e2[1]; 
     auto & e4 = e3[2]; 
     e4 = 100; 

thay vì truy cập cùng một lúc. Sau đó, bước qua với trình gỡ lỗi và kiểm tra các loại e1-e4. e1 sẽ có loại int (&) [2][3] thay vì array<int, 2, 3> &.

Để phân bổ chúng trên đống thay vì trên ngăn xếp, trong lớp của bạn khai báo con trỏ đến OneDimensionDownArrayT thay vì mảng của chúng, xác định các hàm tạo và một desctructor sẽ chăm sóc phân bổ/deallocating mảng của bạn. Nó có thể trông giống như sau:

template <class T, unsigned PrimaryD, unsigned ... RestD> 
    struct array <T, PrimaryD, RestD...> { 
     typedef typename array<T, RestD...>::type OneDimensionDownArrayT; 

     array():data(new OneDimensionDownArrayT[PrimaryD]){} 
     ~array() { 
      delete[] data; 
     } 

     OneDimensionDownArrayT * data; 

     OneDimensionDownArrayT& operator[] (int i) { 
      OneDimensionDownArrayT& a = data[i]; 
      return a; 
     } 
    }; 

Bạn cũng sẽ muốn xác định hàm tạo bản sao, di chuyển hàm tạo và toán tử gán cho lớp của bạn. Việc triển khai này sẽ chiếm không gian ít hơn nhiều, nhưng tổng dung lượng bộ nhớ hơi nhiều hơn vì bạn cũng cần không gian cho các con trỏ cũng như các mảng.

+0

Giải pháp này không hiệu quả đối với các mảng rất lớn như a1 [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]. Bởi vì bên trong mỗi đối tượng nó tạo ra một đối tượng mảng khác khi kích thước kích thước tăng mức sử dụng bộ nhớ sẽ rất lớn. – Alper

+0

Không có vấn đề gì bạn làm, bạn cần phải phân bổ không gian cho 10! các đối tượng. Nếu bạn đang hết dung lượng trên ngăn xếp, hãy thử sử dụng vùng đệm (cấp phát bộ nhớ động). – SirGuy

+0

mảng typedef OneDimensionDownArrayT; hoạt động nhưng theo đối tượng của mỗi kích thước nó tạo ra và mảng đối tượng và nó sẽ tiêu thụ bộ nhớ unnessary. Có hơn 10 đối tượng vì nó là mảng đa chiều. cách tôi có thể phân bổ động => typedef mảng OneDimensionDownArrayT; – Alper

1

Nếu bạn muốn sử dụng [] toán tử liên tiếp một mảng đa chiều, thì mỗi [] phải trả về mảng (một ít) hai chiều.

Nếu loại mảng đa chiều của bạn là:

template <class Type, int dim> MArray; 

Sau đó, một MArray<SomeType, n>::operator[] phải trả lại một MArray<SomeType, n-1>. Với một trường hợp đặc biệt cho mảng 1-D đặc biệt của bạn trả về một đối tượng (tốt nhất là tham chiếu) hoặc một mảng 2-D trả về một mảng 1-D riêng. Ví dụ này sử dụng ký pháp quá đơn giản, nhưng điều quan trọng là một n-D [] -operator trả về mảng (n-1) -D.