2009-07-26 14 views
17

Czy istnieje standardowy sposobem na dostęp do podstawowych pojemnik stack, queue, priority_queue?Czy istnieje sposób dostępu do podstawowego kontenera adapterów kontenerowych STL?

Znalazłem metody nazywanej: _Get_container() w VS2008 realizacji stack i queue, ale nikt do priority_queue! Myślę, że i tak nie jest to standard.

Ponadto wiem, że to głupie pytanie! gdzie mogę znaleźć oficjalną dokumentację standardowej biblioteki?


Tylko dla wyjaśnienia, nie próbowałem zepsuć podstawowego pojemnika. Wszystko, co starałem się zrobić to w ten sposób:

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; 

Mam nadzieję, że widać, że _Get_container() nie jest standardem, a nie ma nikogo na priority_queue w VS2008 realizacji.

+0

nie dokładnie to, czego potrzebujesz, ale kolejka/stack/priority_queue mają ** chroniony ** element "c", który jest podstawowym kontenerem, więc jeśli dziedziczysz z dowolnego z nich, możesz uzyskać do niego dostęp bezpośrednio . –

+0

@Evan Ciekawe! Czy to oznacza, że ​​adaptery są przeznaczone do rozszerzenia poprzez dziedziczenie? Jeśli tak, dlaczego nie ma wirtualnego dtor? –

+0

Ponadto, chronione dane to nie nie w mojej książce - jestem trochę rozczarowany tym! –

Odpowiedz

14

Zauważyłem następujące rozwiązanie gdzieś w internecie i używam go w moich projektach:

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; 
} 

Miłej zabawy :).

+0

Podoba mi się ten włamywacz. Dzięki ;) – AraK

3

Nie, nie ma standardowego sposobu robienia tego. Jeśli chodzi o dostęp do standardu, nie jest on dostępny w sieci, trzeba kupić kopię! Istnieją jednak różne kopie wersji roboczych: available here.

+0

Thanx Neil, myślę, że kupię dokumentację :) – AraK

1

Mam nadzieję, że nie ma sposobu na uzyskanie dostępu do podstawowego kontenera kolejki priorytetowej. Gdybyś mógł wtedy zepsuć wewnętrzną strukturę sterty kolejki priorytetowej. W każdym razie punktem tych adapterów jest to, że są one tylko minimalnym interfejsem stosu lub kolejki, a wszystkie inne rzeczy są abstrakcyjne. Więc jeśli potrzebujesz użyć innych funkcji, powinieneś użyć oryginalnego pojemnika bezpośrednio.

Jeśli chodzi o dokumentację STL, można zajrzeć do dokumentacji SGI STL here. Istnieje kilka różnic między STL STL a standardem C++, ale są one najczęściej odnotowywane na tej stronie. Ponadto, jest dokumentacją wiki biblioteki C++, która staje się bardziej kompletna.

+0

Rozumiem twój punkt widzenia. Próbuję to napisać ogólną funkcję, która przesyła zawartość stosu, kolejki i parametru priority_queue. To tylko dla zabawy, więc nie ma problemu :) – AraK

2

This SGI page to najbardziej "oficjalna" dokumentacja dostępna online, jak sądzę.

Powodem, dla którego nie można uzyskać bezpośredniego dostępu do podstawowego kontenera, jest to, że adapter zmienia wzorzec użycia, a posiadanie dostępnych metod bazowego kontenera naruszyłoby ten nowy wzorzec użytkowania. Na przykład:

2 To ograniczenie jest jedynym powodem, dla którego w ogóle istnieje kolejka. Każdy pojemnik, który jest zarówno przednią sekwencją wstawiania, jak i tylną sekwencją wstawiania, może być używany jako kolejka; deque, na przykład, ma funkcje członkowskie front, back, push_front, push_back, pop_front i pop_back Jedynym powodem użycia kolejki adaptera kontenera zamiast kontenera kontenera jest wyjaśnienie, że wykonywane są tylko operacje kolejkowania, i żadne inne operacje. http://www.sgi.com/tech/stl/queue.html

Jeśli chcesz, aby ominąć tę funkcję projektowania, można zrobić coś takiego:

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

Zwykle powinieneś komponować pojemniki, a nie czerpać z nich. Nie mają na przykład wirtualnych destruktorów. – GManNickG

+0

Uzgodnione. Jednak w tym przypadku nie jesteśmy zainteresowani destruktorami, a przy użyciu dziedziczenia unikamy konieczności definiowania interfejsu 'queue' jako metod proxy. –

2

Zgodnie z ogólną zasadą, każdy identyfikator, który rozpoczyna się od podkreślenia jest rozszerzeniem sprzedawca lub specyficzne szczegół implementacji. Tak więc _Get_container() jest tylko dodatkiem wprowadzonym przez Microsoft, ponieważ uprościł ich implementację. Nie jest przeznaczony do użycia.

Gdzie znaleźć dokumentację, jest podzielona na kilka części.

Autorytatywne źródło jest oczywiście standardem językowym. Jak powiedział Neil Butterworth, dostępne są kopie robocze za darmo w Internecie (które są nadal bardzo przydatne, różnice od ostatecznej wersji są naprawdę minimalne). Alternatywnie możesz kupić kopię. Powinien być dostępny od dowolnej organizacji reprezentującej ISO w twoim kraju (i prawdopodobnie z bajillionu także z innych źródeł). Dokument, którego szukasz, to ISO/IEC 14882:2003 Programming Language C++. (14882 jest standardową liczbą, 2003 to rok ostatniej rewizji, jeśli natkniesz się na wersję z 1998 roku, możesz jej również użyć.Różnice są naprawdę śmiesznie małe pomiędzy tymi dwoma, i w zasadzie to tylko kilka wyjaśnień. prawdopodobnie najlepiej trzymać się z daleka od wersji roboczych dla C++ 0x, ponieważ zmiany są znacznie bardziej rozległe)

Poza tym, każda implementacja standardowej biblioteki jest wymagana do udokumentowania dużej liczby szczegółów (zdefiniowane przez implementację zachowanie, rzeczy, które nie są określone w standardzie, ale pozostają w gestii implementatora biblioteki). Ponadto większość z nich przygotowała szczegółową dokumentację całej biblioteki.

Firma Microsoft udostępnia szczegółową dokumentację na temat MSDN. Dokumentacja przestrzega standardu i wyraźnie zaznacza wszystkie niestandardowe rozszerzenia, aby wiedzieć, która jest która.

SGI posiada również dokumentację online (chociaż jest starsza, aw niektórych przypadkach nie całkiem dokładna).

IBM ma podobną dokumentację dostępną na swojej stronie internetowej i uważam, że GCC również.

+0

Dzięki jalf to było pomocne :) – AraK

+0

Och, nawet nie zdawałem sobie sprawy, że to było twoje pytanie. Myślałem, że już to wiesz. ;) – jalf

-2

Gdzie mogę znaleźć oficjalne dokumenty standardowej biblioteki?

standard C++ jest dostępna w twardej oprawie, ISBN 0470846747. Projekty Standardu są powszechnie dostępne w postaci pliku PDF, ale musisz uważać, aby dopasować je do oficjalnych wersjach (C++ 98,03, 11 lub 14). Bieżące wersje robocze przekraczają standard C++ 14.

7

Wspomniałem o tym w komentarzu, ale po pewnym myśleniu wydaje się, że jest to rozwiązanie OK. queue/stack/priority_queue (to znaczy wszystkie klasy adapterów) wszystkie mają element protectedc, który jest podstawowym kontenerem (patrz ISO/IEC 14882: 2003 sekcja 23.2.2.4), więc jeśli dziedziczysz z dowolnego z nich, można uzyskać do niego bezpośredni dostęp.

Wiem, że typowa mądrość polega na tym, aby nie dziedziczyć z kontenerów STL z powodu nie-wirtualnych dagów, ale ten przypadek jest wyjątkiem. Celem nie jest przeciążenie funkcjonalności, ale niewielkie rozszerzenia interfejsu adaptera. Oto przykład dodawania możliwości dostępu do podstawowego kontenera.

#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; 
    } 
} 

Niestety, trzeba uciekać się do typu paronomazja do „upgrade” istniejący std::queue<int> * do Adapter<std::queue<int> > * bez typu paronomazja. Technicznie rzecz biorąc, to prawdopodobnie działają dobrze ... ale polecam przeciwko niej:

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   

Więc polecam korzystania typedefs aby łatwo przełączać się między nimi. (Zwróć też uwagę w moim przykładzie, że musisz zmienić tylko 1 linię, aby zmienić ją z queue na stack ze względu na liberalne użycie s. typedef).

3

podstawie accepted answer, bardziej ogólne podejście:

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); 
} 

Jak dowiedziałem się od this answer, .*& jest faktycznie dwóch operatorów, gdzie wskaźnik wynikający z &hack::c (która ma typ ADAPTER::container_type ADAPTER::*) jest celem lub .* operator, aby pobrać sam podstawowy kontener. hack ma dostęp do chronionego elementu, ale po uzyskaniu wskaźnika zabezpieczenia są tracone. Tak więc a.*(&hack::c) jest dozwolone.

0

Możesz napisać podklasę, aby pobrać zmienną składową c. Zobacz ten komentarz z 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; 
Powiązane problemy