2015-11-12 51 views
5

Tôi cố gắng viết một vùng chứa kiểu tùy chỉnh STL. Để đơn giản, hãy nói đó là danh sách. Tôi nhìn lên theo cách tiêu chuẩn để xác định một container như:Lớp lồng nhau làm tham số mẫu

template <typename T, typename A = std::allocator<T> > class mylist; 

Bây giờ, tôi muốn quản lý các nút của danh sách bằng cách sử dụng một lớp lồng nhau:

(inside mylist) 
class node { 
    T data; 
    node *next; 
} 

Đó là sự hiểu biết của tôi mà tôi không cần đặt một thông số template ở phía trước định nghĩa node khi trình biên dịch sẽ khởi tạo các lớp riêng biệt mylist<T,A>::node cho mỗi kết hợp các tham số mẫu của mylist.

Tuy nhiên, bây giờ tôi cần cấp phát bộ nhớ không chỉ cho dữ liệu thuộc loại T mà còn cho trình bao bọc của chúng node. Vì vậy, tôi muốn tham số mẫu mặc định là loại std::allocator<mylist<T>::node>. Vào thời điểm đó, mặc dù, mylist vẫn chưa được công bố và trình biên dịch được hiểu rầu rĩ:

error: `mylist' was not declared in this scope 

Làm thế nào người ta sẽ giải quyết câu hỏi hóc búa này? Có hai ràng buộc:

  • Thông thường, tôi sẽ khai báo lớp bị thiếu mà không khai báo đầy đủ nội dung của lớp. Tuy nhiên, vì nó được lồng vào bên trong thứ tôi muốn khai báo, đây không phải là một lựa chọn.
  • Tôi cần node để lồng nhau vì cần truy cập phiên bản cấp phát mylist. Ví dụ: Tôi có số operator= được khai báo trên node nơi rất nhiều quản lý bộ nhớ diễn ra theo cách đệ quy. Điều này có thể là quá mức cần thiết cho một danh sách và bạn có thể thực hiện điều đó từ bên trong mylist, do đó giảm sự phụ thuộc tham số của node trên A, nhưng nó rất quan trọng đối với cấu trúc dữ liệu tôi đang triển khai.
+1

Có thể đáng xem xét cách g ++ triển khai 'std :: list'. –

+0

Nhìn vào phân bổ 'rebind' – Yakk

Trả lời

2

Không quan trọng đối số loại của trình phân bổ mặc định là gì, chỉ là loại thực tế. Bạn có thể sử dụng rebind_alloc từ std::allocator_traits:

Alloc::rebind<T>::other nếu có, nếu không Alloc<T, Args> nếu điều này AllocAlloc<U, Args>

để có được những gì bạn cần:

template <typename T, typename A = std::allocator<T> > 
class mylist { 
    class node { ... }; 

    using NodeAlloc = typename std::allocator_traits<A>::template rebind_alloc<node>; 
}; 

Và sau đó sử dụng NodeAlloc để có được của bạn node s.Bằng cách này, nếu người dùng không chỉ định một người cấp phát, bạn sẽ nhận được mặc định std::allocator<T> và sau đó sử dụng std::allocator<node>. Đây chính xác là những gì bạn muốn, mà không cần phải phơi bày node.

+0

Và điều này cũng không chính xác cách thư viện chuẩn hoạt động như thế nào? – Walter

0

Tôi cần nút để được lồng vào nhau như nó cần phải truy cập vào dụ cấp phát của mylist

Đừng như vậy chắc chắn. Họ có thể là những người bạn:

template <typename, class> class list; 

template <typename T> 
struct node { 
    // ... 
}; 

template <typename T, class Alloc=std::allocator<T> > 
class list { 
    friend node<T>; 
    // ... 
}; 

Nếu bạn không muốn node là bên ngoài truy cập của tập tin của bạn, chỉ cần bỏ qua nó trong tập tin tiêu đề của bạn (.h/.hpp).

+0

Tôi luôn quên bạn bè ... Tôi quyết định đi với giải pháp' rebind_alloc' mặc dù nó có vẻ phù hợp với vấn đề cụ thể của tôi. – Jonas

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