2009-07-26 35 views
17

Có một số tiêu chuẩn cách truy cập vùng chứa cơ bản của stack, queue, priority_queue?Có cách nào để truy cập hộp chứa bộ tiếp hợp container STL cơ bản không?

Tôi đã tìm thấy một phương pháp được gọi là: _Get_container() trong VS2008 triển khai stackqueue, nhưng không có ai cho priority_queue! Tôi nghĩ rằng nó không phải là tiêu chuẩn anyway.

Ngoài ra, tôi biết đó là một câu hỏi ngớ ngẩn! nơi tôi có thể tìm thấy tài liệu chính thức của thư viện chuẩn?


Chỉ để làm rõ, tôi đã không cố gắng gây rối với vùng chứa bên dưới. Tất cả những gì tôi đã cố gắng để làm được điều này:

template <class Container> 
std::ostream& printOneValueContainer(std::ostream& outputstream, Container& container) 
{ 
    Container::const_iterator beg = container.begin(); 

    outputstream << "["; 

    while(beg != container.end()) 
    { 
     outputstream << " " << *beg++; 
    } 

    outputstream << " ]"; 

    return outputstream; 
} 

// stack, queue 
template 
    < class Type 
    , template<class Type, class Container = std::deque<Type> > class Adapter 
    > 
std::ostream& operator<<(std::ostream& outputstream, const Adapter<Type>& adapter) 
{ 
    return printOneValueContainer(outputstream, adapter._Get_container()); 
} 
. 
. 
. 
std::stack<int> iStack; 
. 
. 
std::cout << iStack << std::endl; 

Tôi hy vọng bạn thấy rằng _Get_container() không phải là tiêu chuẩn, và không có ai cho priority_queue trong VS2008 thực hiện.

+0

không chính xác những gì bạn cần, nhưng hàng đợi/ngăn xếp/priority_queue đều có ** thành viên ** được bảo vệ ** là thùng chứa cơ bản, vì vậy nếu bạn kế thừa từ bất kỳ loại nào, bạn có thể truy cập trực tiếp . –

+0

@Evan Thú vị! Điều này có nghĩa rằng các bộ điều hợp được dự định để mở rộng thông qua thừa kế? Nếu vậy, tại sao không có dtor ảo? –

+0

Ngoài ra, dữ liệu được bảo vệ là không có trong sách của tôi - tôi hơi thất vọng về điều này! –

Trả lời

14

tôi phát hiện các giải pháp sau đây ở đâu đó trên web và tôi đang sử dụng nó trong các dự án của tôi:

template <class T, class S, class C> 
    S& Container(priority_queue<T, S, C>& q) { 
     struct HackedQueue : private priority_queue<T, S, C> { 
      static S& Container(priority_queue<T, S, C>& q) { 
       return q.*&HackedQueue::c; 
      } 
     }; 
    return HackedQueue::Container(q); 
} 

int main() 
{ 
    priority_queue<SomeClass> pq; 
    vector<SomeClass> &tasks = Container(pq); 
    return 0; 
} 

Có :) vui vẻ.

+0

Tôi thích người đàn ông hack này. Cảm ơn ;) – AraK

3

Không, không có cách nào tiêu chuẩn để làm điều đó. Để truy cập vào tiêu chuẩn, nó không có sẵn trên web, bạn phải mua một bản sao! Tuy nhiên, có nhiều bản nháp khác nhau available here.

+0

Thanx Neil, tôi nghĩ tôi sẽ mua tài liệu :) – AraK

1

Tôi chắc chắn hy vọng không có cách nào để truy cập vùng chứa cơ bản của hàng đợi ưu tiên. Nếu bạn có thể sau đó bạn có thể mess lên cấu trúc heap nội bộ của hàng đợi ưu tiên. Trong mọi trường hợp, điểm của các bộ điều hợp đó là chúng chỉ chỉ trình bày cho bạn giao diện tối thiểu của chồng hoặc hàng đợi và tóm tắt tất cả những thứ khác. Vì vậy, nếu bạn cần sử dụng bất kỳ tính năng nào khác, bạn nên sử dụng vùng chứa ban đầu một cách trực tiếp.

Đối với tài liệu của STL, bạn có thể xem tài liệu về STL here của SGI. Có một vài khác biệt giữa STL của SGI và một trong tiêu chuẩn C++, nhưng chúng hầu như được ghi chú trên trang đó. Ngoài ra, là tài liệu wiki của thư viện C++ đang trở nên hoàn chỉnh hơn.

+0

Tôi thấy quan điểm của bạn. Những gì tôi đang cố gắng làm là viết một hàm chung để truyền nội dung của ngăn xếp, hàng đợi và priority_queue. Nó chỉ là cho vui vì vậy không có vấn đề :) – AraK

2

This SGI page là tài liệu "chính thức" nhất có sẵn trực tuyến, tôi tin.

Lý do bạn không thể truy cập trực tiếp vào vùng chứa cơ bản là bộ điều hợp thay đổi mẫu sử dụng và có các phương pháp của vùng chứa cơ bản sẵn có sẽ vi phạm mẫu sử dụng mới đó. Ví dụ:

2 Hạn chế này là lý do duy nhất cho hàng đợi tồn tại. Bất kỳ vùng chứa nào vừa là chuỗi chèn trước và chuỗi chèn lại có thể được sử dụng làm hàng đợi; deque, ví dụ, có các hàm thành viên front, back, push_front, push_back, pop_front và pop_back Lý do duy nhất để sử dụng hàng đợi bộ chuyển đổi container thay vì deque container là làm rõ rằng bạn chỉ thực hiện các hoạt động xếp hàng và không có hoạt động. http://www.sgi.com/tech/stl/queue.html

Nếu bạn muốn để có được xung quanh tính năng thiết kế này, bạn có thể làm điều gì đó như:

template <typename T> 
class clearable_queue : public std::queue<T> 
{ 
public: 
    void clear() { c.clear(); } 
}; 
+0

Thông thường bạn nên soạn container thay vì lấy được từ chúng. Ví dụ: họ không có trình phá hủy ảo. – GManNickG

+0

Đồng ý. Tuy nhiên trong trường hợp này, chúng ta không quan tâm đến destructors, và bằng cách sử dụng thừa kế, chúng ta tránh phải định nghĩa giao diện 'queue' như các phương thức proxy. –

2

Theo nguyên tắc chung, bất kỳ định rằng bắt đầu với một dấu gạch dưới là một phần mở rộng nhà cung cấp cụ hoặc chi tiết triển khai. Vì vậy, _Get_container() chỉ là một bổ sung được thực hiện bởi Microsoft bởi vì nó đơn giản hóa việc thực hiện của họ. Nó không có ý định được sử dụng.

Đối với nơi tìm tài liệu, nó được chia thành nhiều phần.

Nguồn có thẩm quyền là, tất nhiên, tiêu chuẩn ngôn ngữ. Như Neil Butterworth cho biết, có những bản nháp có sẵn cho trực tuyến miễn phí (mà vẫn còn rất hữu ích. Sự khác biệt so với phiên bản cuối cùng là rất nhỏ). Ngoài ra, bạn có thể mua một bản sao. Nó sẽ có sẵn từ bất kỳ tổ chức nào đại diện cho ISO ở quốc gia của bạn (và có thể từ một nguồn khác bajillion). Tài liệu bạn đang tìm kiếm là ISO/IEC 14882:2003 Programming Language C++. (14882 là số tiêu chuẩn. 2003 là năm của bản sửa đổi cuối cùng. Nếu bạn gặp phiên bản năm 1998, bạn cũng có thể sử dụng nó. Sự khác biệt thực sự nhỏ giữa hai điều này, và về cơ bản chỉ là một vài giải thích. có lẽ tốt nhất để tránh xa các bản nháp cho C++ 0x, vì các thay đổi có nhiều hơn nữa rộng rãi)

Ngoài ra, mọi việc thực hiện thư viện chuẩn đều được yêu cầu ghi lại một số lượng lớn chi tiết (thực hiện xác định hành vi, những thứ không được chỉ định trong tiêu chuẩn, nhưng được để lại cho người triển khai thư viện). Và ngoài ra, hầu hết trong số họ cũng đưa ra một tài liệu chi tiết của toàn bộ thư viện là tốt.

Microsoft có tài liệu chi tiết có sẵn trên MSDN. Tài liệu này tôn trọng tiêu chuẩn và đánh dấu rõ ràng tất cả các phần mở rộng không chuẩn để bạn biết đó là cái gì.

SGI cũng có tài liệu trực tuyến (mặc dù nó cũ hơn và trong một số trường hợp, không hoàn toàn chính xác).

IBM có tài liệu tương tự có sẵn trên trang web của họ và tôi tin rằng GCC cũng vậy.

+0

Cảm ơn jalf đó là hữu ích :) – AraK

+0

Ồ, thậm chí không nhận ra đây là câu hỏi của bạn. Nghĩ rằng bạn đã biết công cụ này rồi. ;) – jalf

-2

nơi tôi có thể tìm thấy tài liệu chính thức của thư viện chuẩn?

Chuẩn C++ có sẵn trong bìa cứng, ISBN 0470846747. Bản nháp chuẩn có sẵn dưới dạng PDF, nhưng bạn sẽ phải cẩn thận để phù hợp với các phiên bản chính thức (C++ 98,03, 11 hoặc 14). Các bản nháp hiện tại vượt quá tiêu chuẩn C++ 14.

7

Tôi đã đề cập đến nó trong một nhận xét, nhưng sau một số suy nghĩ, nó có vẻ là một giải pháp OK. queue/stack/priority_queue (nghĩa là tất cả các lớp bộ điều hợp) đều có protected thành viên c là bộ chứa cơ bản (xem ISO/IEC 14882: 2003 phần 23.2.2.4), vì vậy nếu bạn kế thừa từ bất kỳ điều nào trong số này, bạn có thể truy cập trực tiếp.

Tôi biết sự khôn ngoan điển hình là không kế thừa từ các container STL do các dtors phi ảo, nhưng trường hợp này là một ngoại lệ. Mục tiêu không phải là quá tải chức năng, nhưng để làm cho các phần mở rộng nhỏ đến giao diện của bộ điều hợp. Dưới đây là ví dụ về việc thêm khả năng truy cập vào vùng chứa bên dưới.

#include <queue> 
#include <iostream> 

template <class Container> 
class Adapter : public Container { 
public: 
    typedef typename Container::container_type container_type; 
    container_type &get_container() { return this->c; } 
}; 

int main() { 
    typedef std::queue<int> C; 
    typedef Adapter<C> Container; 

    Container adapter; 

    for(int i = 0; i < 10; ++i) { 
     adapter.push(i); 
    } 

    Container::container_type &c = adapter.get_container(); 
    for(Container::container_type::iterator it = c.begin(); it != c.end(); ++it) { 
     std::cout << *it << std::endl; 
    } 
} 

Thật không may, bạn sẽ phải nghỉ mát để gõ-punning để "nâng cấp", một hiện std::queue<int> * đến một Adapter<std::queue<int> > * không có loại punning. Về mặt kỹ thuật, điều này có khả năng sẽ làm việc tốt ... nhưng tôi khuyên bạn nên chống lại nó:

typedef std::stack<int> C; 
    typedef Adapter<C> Container; 
    C stack; 
    // put stuff in stack 
    Container *adapter = reinterpret_cast<Container *>(&stack); 
    Container::container_type &c = adapter->get_container(); 
    // from here, same as above   

Vì vậy, tôi sẽ khuyên bạn sử dụng typedefs để làm cho nó dễ dàng để trao đổi giữa hai người. (Cũng lưu ý trong ví dụ của tôi rằng bạn chỉ cần thay đổi 1 dòng để thay đổi nó từ một queue thành một số stack do sử dụng tự do typedef s).

3

Dựa trên accepted answer, một cách tiếp cận tổng quát hơn:

template <class ADAPTER> 
typename ADAPTER::container_type & get_container (ADAPTER &a) 
{ 
    struct hack : ADAPTER { 
     static typename ADAPTER::container_type & get (ADAPTER &a) { 
      return a.*&hack::c; 
     } 
    }; 
    return hack::get(a); 
} 

Như tôi đã học được từ this answer, .*& thực sự là hai nhà khai thác, nơi con trỏ kết quả từ &hack::c (mà đã gõ ADAPTER::container_type ADAPTER::*) là mục tiêu hoặc Nhà điều hành .* để truy xuất vùng chứa cơ bản. hack có quyền truy cập vào thành viên được bảo vệ, nhưng sau khi thu được con trỏ, bảo vệ bị mất. Vì vậy, a.*(&hack::c) được cho phép.

0

Bạn có thể viết một phân lớp để truy lục biến thành viên c. Xem nhận xét này từ libstdC++.

protected: 
/** 
* 'c' is the underlying container. Maintainers wondering why 
* this isn't uglified as per style guidelines should note that 
* this name is specified in the standard, [23.2.3.1]. (Why? 
* Presumably for the same reason that it's protected instead 
* of private: to allow derivation. But none of the other 
* containers allow for derivation. Odd.) 
*/ 
_Sequence c; 
Các vấn đề liên quan