2012-03-25 41 views
11

Tôi có một kiểu dữ liệu đệ quy như thế này:templated kiểu dữ liệu đệ quy

template<typename T> 
struct SomeType { 
    std::map<T, SomeType<T>> mapping; 
}; 

SomeType<int> foo; 

này hoạt động tốt, nhưng thay thế std::map với std::unordered_map kết quả trong một lỗi biên dịch do một loại không đầy đủ. Tôi (hoặc gcc) có mắc lỗi ở đâu đó không? hay đây chỉ là một phần của tiêu chuẩn?

Tôi cũng muốn có vùng chứa bên trong được xác định bởi thông số mẫu (như std::stackstd::queue), nhưng tôi không thể tìm ra cách để làm điều đó vì yêu cầu SomeType đã được xác định.

Incomplete dụ:

template<typename T, typename C = std::map<T, SomeType<[???]>>> 
struct SomeType { 
    C mapping; 
}; 

SomeType<int, [???]> foo; 

Tôi biết điều này có thể được thực hiện với gián tiếp runtime, nhưng đó không phải là những gì tôi đang tìm kiếm.

+1

container tiêu chuẩn thư viện mẫu yêu cầu bạn phải nhanh chóng chúng với các loại hoàn chỉnh; tất cả những thứ khác là hành vi không xác định. Bạn phải sống với điều đó. Bạn có thể sử dụng một giải pháp pimpl để làm việc xung quanh đó, mặc dù. –

+0

@KerrekSB Vậy sao? Chết tiệt, tôi thường xuyên viết những cây n-ary có các nút đã được triển khai dưới dạng 'std :: vector children'. –

+0

@KonradRudolph: Vâng, bạn phải đảm bảo rằng tại thời điểm khởi tạo, loại hoàn tất. Đó có thể là một vấn đề tinh tế. –

Trả lời

7

Lớp học của bạn chưa hoàn thành ở bất kỳ đâu trước khi kết quả cuối cùng là }. Vì vậy, thành viên mapping đang sử dụng loại không đầy đủ SomeType trong các đối số mẫu của loại của nó.

The standard does not allow this, and it is pure luck that it works with some STL containers.

câu hỏi thứ hai của bạn thuộc câu trả lời giống nhau - đó là bất hợp pháp để làm điều đó ở nơi đầu tiên.

+0

Hmm. Rất tiếc, tôi không hiểu lý do của bài viết về lý do tại sao 'std :: map ' với các loại không hoàn chỉnh không thể hoạt động theo nguyên tắc. Điều này không giống như 'std :: vector >', * có thể * hoạt động theo nguyên tắc ('std :: pair ' chưa hoàn thành)? Cũng vậy với các container khác. –

+0

Nếu điều này cần giải thích, tôi đề nghị mở một phòng chat, nó không khó, chỉ cần không thích hợp cho phần ý kiến ​​... Bây giờ, làm thế nào để tôi mở một phòng chat một cách rõ ràng về điều này ... – Irfy

+1

Hãy trò chuyện ở đây: http://chat.stackoverflow.com/rooms/9282/stl-with-incomplete-types – Irfy

4

Bạn không thể xác định mẫu có tham số mặc định đệ quy vì các lý do rõ ràng. Bạn cũng không thể khởi tạo các mẫu container thư viện chuẩn trên các kiểu không đầy đủ, vì tiêu chuẩn nói như vậy (nếu không hành vi không xác định). Thành ngữ PIMPL thông thường có thể trợ giúp, mặc dù:

#include <map> 
#include <memory> 
template <typename T> class SomeType 
{ 
    typedef std::map<T, SomeType<T>> map_type; 
    typedef std::unique_ptr<map_type> map_ptr; 
    map_ptr pimpl; 
public: 
    SomeType() : pimpl(new map_type) { } 
}; 
+1

Thư viện boost :: container cung cấp các lựa chọn thay thế cho hầu hết các loại STL cho phép các tập tin đệ quy không hoàn chỉnh. Nó hiện không cung cấp một unordered_map – mark

+0

@mark: Cảm ơn, đó là điều tốt để biết! –

3

Trong khi bạn không thể sử dụng loại không đầy đủ với vùng chứa, bạn có thể làm điều đó với con trỏ thông minh. Và trong khi bạn không thể tạo ra các loại mẫu với các thông số loại không xác định, bạn có thể sử dụng một số thủ thuật ở đây:

template<typename T, template <typename U, typename V, typename... Args> class Container = std::unordered_map > 
struct SomeType { 
    Container<T, std::unique_ptr<SomeType> > mapping; 
}; 
+0

Có thể thay đổi dòng đầu tiên sao cho giá trị mặc định cho Vùng chứa sẽ là tiêu chuẩn :: vector? –

+0

@NielsLohmann, về mặt kỹ thuật bạn có thể viết 'template class Container = std :: vector>', nhưng nó sẽ không nhất quán với 'std :: unordered_map' hơn. Bởi vì map là _assosiative_ conrtainer và vector chỉ là một mảng. – Lol4t0

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