2011-11-30 34 views
16

Đôi khi nó là hữu ích để khởi tạo một container tiêu chuẩn với một loại không đầy đủ để có được một cấu trúc đệ quy:Các mẫu vùng chứa tiêu chuẩn có thể được khởi tạo với các loại không đầy đủ không?

struct multi_tree_node { // Does work in most implementations 
    std::vector<multi_tree_node> child; 
}; 

struct trie_node { // Does not work in most implementations 
    std::map< char, trie_node > next; 
}; 

này có xu hướng làm việc vì container không có các thành viên của kiểu value_type hoặc thành viên chức năng mà vượt qua hoặc trả lại bất kỳ value_type đối tượng theo giá trị. Tiêu chuẩn dường như không nói nhiều về các đối số mẫu không đầy đủ, nhưng có một chút trong C++ 11 §17.6.4.8 [lib.res.on.functions], "các yêu cầu đối với các chức năng khác":

Cụ thể, hiệu ứng không xác định trong các trường hợp sau:… nếu một kiểu không đầy đủ (3.9) được sử dụng làm đối số mẫu khi tạo thành phần mẫu, trừ khi được phép cụ thể cho thành phần đó.

Điều này có làm cho các cấu trúc trên không hợp pháp, mặc dù các cảnh báo không nằm trong phạm vi khối? Điều này có nằm trong "các hoạt động trên các kiểu được sử dụng để khởi tạo các thành phần mẫu thư viện chuẩn" (còn 17.6.4.8) không? Hoặc là một thực hiện thư viện bị cấm để phát sinh các mẫu instantiations có thể thất bại cho các loại không đầy đủ khi tất cả các yêu cầu cụ thể instantiations thành công?

Chỉnh sửa: Vì chỉ có các chức năng mới có thể gọi và khởi tạo các chức năng khác, giới hạn "hoạt động trên các loại ..." cho những người trong phạm vi khối dường như giữ nội dung của hàm thành viên với yêu cầu khắt khe hơn nội dung của chữ ký và thành viên định nghĩa lớp. Xét cho cùng, chắc chắn không có ý nghĩa với việc làm bất cứ điều gì với một multi_tree_node cho đến khi loại hoàn tất. Và điều này mở rộng đến std::unique_ptr hỗ trợ rõ ràng đối số loại không đầy đủ, ngay cả khi được sử dụng trong phạm vi khối.

Chỉnh sửa 2: Phục vụ tôi ngay vì không bận tâm kiểm tra ví dụ trie_node - và tôi thậm chí đã thử nó trước đây. Nó giống như ví dụ về vỡ trong the article mà @Ise liên kết. Tuy nhiên, trong khi bài viết dường như cho rằng "không có gì giống như vậy có thể hiệu quả", giải pháp có vẻ đơn giản với tôi - lớp nội bộ của tree_node phải là một mẫu không phải là thành viên, không phải là một lớp không phải mẫu thành viên.

Dù sao, bài viết đó thiết lập mục đích thiết kế khá tốt, vì vậy tôi đoán nitpick của tôi về việc nằm trong phân nhóm "yêu cầu về chức năng" chỉ là như vậy.

+1

Tôi không thấy bất kỳ loại không hoàn chỉnh nào trong mã bạn đã đăng? –

+1

@JohnDibling: 'trie_node' chưa hoàn thành trong khi xác định' next'. –

+1

@JohnDibling Trong phạm vi riêng của một lớp, nó chưa hoàn chỉnh. – Potatoswatter

Trả lời

4

Cá nhân, tôi cảm nhận được từ ngữ instantiating trong 17.6.4.8/2 là một chút mơ hồ, nhưng theo this article, ý định của tiêu chuẩn dường như không cho phép kiểu dữ liệu đệ quy sử dụng container tiêu chuẩn.

Trên một lưu ý liên quan, VC2005 vấn đề lỗi cho class C { std::deque<C> x; };, trong khi nó biên dịch class C { std::vector<C> x; }; ...
Tuy nhiên, trong sự hiểu biết của tôi, hạn chế này chỉ dành cho việc mở rộng tự do thực hiện các container tiêu chuẩn. Vì vậy, như Kerrek SB được đề cập, có thể có các vùng chứa cho phép cấu trúc dữ liệu đệ quy và Boost.Container dường như cung cấp cơ sở này.

10

Đây là nỗ lực của tôi tại một giải thích:

Tiêu chuẩn đơn giản nói rằng bạn không phải làm điều này, mặc dù bất kỳ thực hiện cụ thể nhất định có thể không có vấn đề hỗ trợ một công trình như vậy. Nhưng hãy tưởng tượng ví dụ nếu ai đó muốn viết một tối ưu hóa "vector nhỏ", theo đó một vector luôn chứa không gian cho, ví dụ, năm phần tử. Ngay lập tức bạn sẽ gặp rắc rối bởi vì bạn có loại tự tham chiếu. Điều này sẽ là một vấn đề ngay cả khi vectơ sử dụng một số loại phân nhánh tĩnh phụ thuộc vào kích thước của kiểu giá trị.

Do đó, để không loại trừ việc triển khai từ việc bao gồm các công trình như vậy, tiêu chuẩn chỉ đơn giản nói rằng bạn chỉ phải sử dụng các loại hoàn chỉnh. Nói cách khác, thực tế là hầu hết các thùng chứa chỉ chứa tham chiếu hoặc con trỏ đến loại giá trị là chi tiết triển khai thay vì yêu cầu chuẩn.

Chỉ cần làm rõ điều này: nếu bạn xác định mẫu lớp riêng của mình, bạn hoàn toàn có thể thiết kế mẫu theo cách hỗ trợ rõ ràng các loại không đầy đủ. Ví dụ từ tiêu chuẩn là std::unique_ptr, điều này hoàn toàn hài lòng với thông số loại không đầy đủ T[] (hoặc thậm chí void).

+0

+1 ví dụ tuyệt vời, nhưng tôi sẽ đợi một số giải thích tiêu chuẩn initio ... mã của tôi chắc chắn vi phạm yêu cầu được trích dẫn, nhưng phần khác của câu hỏi là liệu yêu cầu có áp dụng bên ngoài phạm vi chức năng/khối hay không. (Vì chỉ có các chức năng mới có thể gọi và khởi tạo các chức năng khác, điều này dường như chứa nội dung của các hàm thành viên theo một tiêu chuẩn khác so với nội dung của chữ ký và định nghĩa lớp thành viên.) – Potatoswatter

+0

"vector nhỏ" không phải là một ví dụ tuyệt vời; tối ưu hóa đó không được phép theo tiêu chuẩn. –

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