2012-04-24 16 views
7

Chương trình 1:Tại sao tôi không thể xây dựng một hàng đợi/ngăn xếp với các danh sách khởi tạo kèm cặp ngoặc nhọn? (C++ 11)

#include <iostream> 
#include <cstdlib> 
#include <vector> 

int main(){ 

    //compiles successfully 
    std::vector<int> vec{1,2,3,4,5}; 

    return EXIT_SUCCESS; 
} 

Chương trình 2:

#include <iostream> 
#include <cstdlib> 
#include <queue> 

int main(){ 

    //compiler error 
    std::queue<int> que{1,2,3,4,5}; 

    return EXIT_SUCCESS; 
} 

Thông báo lỗi:

main.cpp: In function ‘int main()’: 
main.cpp:7:31: error: no matching function for call to ‘std::queue<int>::queue(<brace-enclosed initializer list>)’ 
main.cpp:7:31: note: candidates are: 
/usr/include/c++/4.6/bits/stl_queue.h:141:7: note: std::queue<_Tp, _Sequence>::queue(_Sequence&&) [with _Tp = int, _Sequence = std::deque<int, std::allocator<int> >] 
/usr/include/c++/4.6/bits/stl_queue.h:141:7: note: candidate expects 1 argument, 5 provided 
/usr/include/c++/4.6/bits/stl_queue.h:137:7: note: std::queue<_Tp, _Sequence>::queue(const _Sequence&) [with _Tp = int, _Sequence = std::deque<int, std::allocator<int> >] 
/usr/include/c++/4.6/bits/stl_queue.h:137:7: note: candidate expects 1 argument, 5 provided 
/usr/include/c++/4.6/bits/stl_queue.h:92:11: note: std::queue<int>::queue(const std::queue<int>&) 
/usr/include/c++/4.6/bits/stl_queue.h:92:11: note: candidate expects 1 argument, 5 provided 
/usr/include/c++/4.6/bits/stl_queue.h:92:11: note: std::queue<int>::queue(std::queue<int>&&) 
/usr/include/c++/4.6/bits/stl_queue.h:92:11: note: candidate expects 1 argument, 5 provided 

Câu hỏi:
tại sao hàng đợi không thể được khởi chạy như vectơ?
Tôi cho rằng chúng không phải là vùng chứa chuỗi, nhưng tại sao điều đó lại quan trọng?
Tôi chắc chắn có lý do chính đáng, nhưng tôi không thể tìm thấy bất kỳ giải thích nào.

gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1

+0

Bạn có thể kiểm tra tham chiếu về vùng chứa [tại đây] (http://www.cplusplus.com/reference/stl/). Bạn cũng có thể xem xét boost :: assign library [here] (http://www.boost.org/doc/libs/1_42_0/libs/assign/doc/index.html). –

Trả lời

18

Tôi không nghĩ rằng nó thực sự có liên quan đến việc sử dụng bộ điều hợp container thay vì thùng chứa (mặc dù tôi thừa nhận tôi không chắc chắn chính xác lý do tại sao hàm dựng chính xác bị bỏ qua).

Khi bạn sử dụng một danh sách initializer chuẩn bị tinh thần với std::vector, bạn đang sử dụng này (mới trong C++ 11) constructor:

vector(initializer_list<T>, const Allocator& = Allocator()); 

Nhìn vào định nghĩa của std::queue, các nhà thầu có sẵn là:

explicit queue(const Container&); 
explicit queue(Container&& = Container()); 
template <class Alloc> explicit queue(const Alloc&); 
template <class Alloc> queue(const Container&, const Alloc&); 
template <class Alloc> queue(Container&&, const Alloc&); 
template <class Alloc> queue(const queue&, const Alloc&); 
template <class Alloc> queue(queue&&, const Alloc&); 

Một nhà xây dựng tham gia một initialization_list vắng mặt rõ ràng.

Tôi khá chắc chắn rằng mặc dù là bộ điều hợp vùng chứa, nhưng hàm tạo như vậy sẽ không quan trọng nếu nó được mong muốn. Chỉ cần ví dụ:

#include <deque> 
#include <initializer_list> 
#include <iostream> 

template <class T, class container=std::deque<T> > 
class myqueue { 
    container data; 
public: 
    explicit myqueue(std::initializer_list<T> t) : data(t) {} 
    void pop() { data.pop_front(); } 
    T front() const { return data.front(); } 
    bool empty() const { return data.empty(); } 
}; 

int main(){ 
    myqueue<int> data {1, 2, 3, 4}; 
    while (!data.empty()) { 
     std::cout << data.front() << "\n"; 
     data.pop(); 
    } 
    return 0; 
} 

g ++ 4.7 chấp nhận này mà không có bất kỳ vấn đề, và tạo ra chính xác đầu ra mà bạn mong đợi:

1 
2 
3 
4 

Mặc dù tôi đã không thử nghiệm với bất kỳ trình biên dịch khác, tôi có thể' t thấy lý do nào khác trình biên dịch sẽ không làm việc tốt với điều này là tốt (miễn là họ thực hiện các tính năng cần thiết, tất nhiên).

Chỉnh sửa: Tôi vừa xem qua các giấy tờ ủy ban đề xuất thêm initalizer_lists vào C++ (ví dụ: N1890, N1919, N2100, N2215, N2220) và trông giống như một sự giám sát đơn giản. Nhiều giấy tờ trước đây mang tính khái niệm hơn, nhưng N2220 có số lượng ngôn ngữ đề xuất công bằng cho bài báo. Đối với std::array (cho một ví dụ), nó chỉ ra rằng không cần thay đổi. Sau đó, nó đi qua deque, vector, [unordered_][multi_](set|map) và hiển thị các thay đổi cần thiết cho mỗi - nhưng không có đề cập nào được tạo thành từ chồng hoặc xếp hàng, theo cả hai hướng. Không có đề xuất để thêm hỗ trợ cho std::initializer_list, cũng không (như std::array) lý do cho sự thiếu sót của chúng.

Tôi muốn kết luận rằng đó là một sự giám sát đơn giản, có thể bị trượt vì hai lý do: 1) các bộ điều hợp gần như, nhưng không hoàn toàn là thùng chứa và 2) các lớp bộ điều hợp dường như không được sử dụng toàn bộ rất nhiều, do đó, quên chúng có lẽ khá dễ dàng (và, tất nhiên, lý do thứ ba phổ biến bao giờ hết: hầu hết các thành viên ủy ban hoạt động đang làm việc quá mức).

Edit2: Tôi có lẽ nên thêm chi tiết thêm một: từ stackqueue có thể vừa chấp nhận một container cho việc khởi tạo, bạn có thể khá dễ dàng làm điều gì đó như:

std::stack<int> data(std::vector<int>{1,2,3,4}); 

này hơi dài dòng, nhưng khó có khả năng gây ra bất kỳ tổn thất hiệu quả (container sẽ được thông qua như là một tham chiếu rvalue, do đó, đại diện của nó sẽ được "bị đánh cắp" thay vì sao chép). Mặc dù vậy, có một lưu ý: nếu loại vùng chứa bạn sử dụng không khớp với vùng chứa bên dưới bộ điều hợp vùng chứa, bạn sẽ nhận được bản sao thay vì di chuyển (và do đó, có thể mất hiệu quả).

+0

con trai của một khẩu súng. Tôi vừa hoàn thành việc viết mã giống hệt nhau –

+2

Thay vì thực hiện tất cả chính mình, bạn có thể kế thừa bộ điều hợp vùng chứa mà bạn cần và thêm hàm tạo danh sách khởi tạo. Sử dụng các hàm tạo chuyển tiếp C++ 11 để bạn không phải triển khai các hàm tạo lớp cơ sở. –

+2

Như một câu trả lời bình chọn cho việc cung cấp hai giải pháp khả thi cộng với một bản tóm tắt các giấy tờ tương ứng. –

6

std::queuestd::stack không thực sự container, họ là như vậy gọi là adapter chứa trong đó sử dụng một container (theo mặc định std::deque). Do đó bạn không thể khởi tạo nó như các container khác.

Sửa

Đối với một container để có thể sử dụng một danh sách initializer, nó phải có một constructor lấy một std::initializer_list như là đối số. Các bộ điều hợp container không làm điều đó. Nếu nó có chủ ý hoặc một sự giám sát của ủy ban tiêu chuẩn là lên đến anyones giải thích.

+0

Trong ngắn 'std :: queue',' std :: stack' & 'std :: priorityqueue' là * Container Adapters *, Vùng chứa được xây dựng bằng cách sử dụng các thùng chứa thư viện chuẩn khác. –

+1

Tuy nhiên, họ có thể gọi vùng chứa bên dưới bằng danh sách khởi tạo. Có lý do tại sao điều này không được thực hiện? – RedX

+0

Tôi có thể khởi tạo std :: deque. Các adapter này có khá nhiều deques với ít chức năng hơn không? Ngoài ra, những gì @RedX đã nói –

8
queue<int> q({1, 2, 3}); 
+0

Tính năng này có hoạt động không? Làm sao? – Narek

+2

đây là một trong những tốt, tôi cho rằng nó hoạt động vì một trong những nhà xây dựng hàng đợi chấp nhận các loại container cơ bản. danh sách khởi tạo trước hết được chuyển đổi thành điều đó, vì trình biên dịch được phép thực hiện một chuyển đổi ngầm, và sau đó hàm tạo của hàng đợi được gọi với vùng chứa được khởi tạo – iggy

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