¿Hay alguna manera de acceder al contenedor subyacente de los adaptadores de contenedor STL?

¿Hay una forma estándar de acceder al contenedor subyacente de stack , queue , priority_queue ?

Encontré un método llamado: _Get_container() en la implementación VS2008 de stack y queue , ¡pero nadie para priority_queue ! Creo que no es estándar de todos modos.

Además, sé que es una pregunta tonta! ¿Dónde puedo encontrar la documentación oficial de la biblioteca estándar?


Solo por aclaración, no estaba tratando de meter la pata con el contenedor subyacente. Todo lo que estaba tratando de hacer es esto:

 template  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 > class Adapter > std::ostream& operator<<(std::ostream& outputstream, const Adapter& adapter) { return printOneValueContainer(outputstream, adapter._Get_container()); } . . . std::stack iStack; . . std::cout << iStack << std::endl; 

Espero que veas que _Get_container() no es estándar, y no hay nadie para priority_queue en la implementación VS2008 .

Vi la siguiente solución en algún lugar de la web y la estoy usando en mis proyectos:

 template  S& Container(priority_queue& q) { struct HackedQueue : private priority_queue { static S& Container(priority_queue& q) { return q.*&HackedQueue::c; } }; return HackedQueue::Container(q); } int main() { priority_queue pq; vector &tasks = Container(pq); return 0; } 

Que te diviertas :).

Lo mencioné en un comentario, pero después de pensarlo, parece ser una solución correcta. queue / stack / priority_queue (es decir, todas las clases de adaptadores) tienen un miembro protected c que es el contenedor subyacente (consulte ISO / IEC 14882: 2003 sección 23.2.2.4), por lo que si hereda alguno de estos, usted puede acceder directamente

Sé que la sabiduría típica es no heredar de contenedores STL debido a dtors no virtuales, pero este caso es una excepción. El objective no es sobrecargar la funcionalidad, sino hacer extensiones menores a la interfaz del adaptador. Aquí hay un ejemplo de cómo agregar la capacidad de acceder al contenedor subyacente.

 #include  #include  template  class Adapter : public Container { public: typedef typename Container::container_type container_type; container_type &get_container() { return this->c; } }; int main() { typedef std::queue C; typedef Adapter 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; } } 

Desafortunadamente, tendrás que recurrir a la escritura de tipos para "actualizar" una std::queue * a un Adapter > * sin tipeo de tipo. Técnicamente, esto funcionaría bien ... pero recomiendo que no:

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

Así que recomendaría usar typedefs para facilitar el intercambio entre los dos. (También observe en mi ejemplo que solo necesita cambiar 1 línea para cambiarla de una queue a una stack debido al uso liberal de typedef s).

Basado en la respuesta aceptada , un enfoque más general:

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

Como aprendí de esta respuesta , .*& realidad son dos operadores, donde el puntero resultante de &hack::c (que tiene el tipo ADAPTER::container_type ADAPTER::* ) es el objective o el operador .* para recuperar el contenedor subyacente sí mismo. hack tiene acceso al miembro protegido, pero después de que se obtiene el puntero, se pierden las protecciones. Entonces a.*(&hack::c) está permitido.

No, no hay una forma estándar de hacer eso. En cuanto al acceso a la norma, no está disponible en la web, ¡tienes que comprar una copia! Sin embargo, hay varias copias de borradores disponibles aquí .

Esta página de SGI es la documentación más “oficial” disponible en línea, creo.

La razón por la que no se puede obtener acceso directo al contenedor subyacente es que el adaptador cambia el patrón de uso, y tener los métodos del contenedor subyacente disponible violaría ese nuevo patrón de uso. Por ejemplo:

2 Esta restricción es la única razón por la que existe la cola. Cualquier contenedor que sea a la vez una secuencia de inserción frontal y una secuencia de inserción posterior puede usarse como una cola; deque, por ejemplo, tiene funciones miembro front, back, push_front, push_back, pop_front y pop_back La única razón para usar la cola del adaptador del contenedor en lugar del contenedor deque es para dejar en claro que está realizando solo operaciones de cola, y ninguna otra operaciones. http://www.sgi.com/tech/stl/queue.html

Si desea evitar esta característica de diseño, puede hacer algo como:

 template  class clearable_queue : public std::queue { public: void clear() { c.clear(); } }; 

Como regla general, cualquier identificador que comience con un guión bajo es una extensión específica del proveedor o un detalle de implementación. Así que _Get_container() es solo una adición hecha por Microsoft porque simplificó su implementación. No está destinado a ser utilizado.

En cuanto a dónde encontrar la documentación, se divide en varias partes.

La fuente autorizada es, por supuesto, el estándar de idioma. Como dijo Neil Butterworth, hay copias en borrador disponibles de forma gratuita en línea (que siguen siendo muy útiles. Las diferencias con respecto a la versión final son realmente mínimas). Alternativamente, puedes comprar una copia. Debería estar disponible desde cualquier organización que represente ISO en su país (y probablemente también desde otras fonts). El documento que está buscando es ISO/IEC 14882:2003 Programming Language C++ . (14882 es el número estándar. 2003 es el año de la última revisión. Si te encuentras con la versión de 1998, también puedes usarla. Las diferencias son realmente ridículas entre las dos, y básicamente equivale a algunas aclaraciones. probablemente sea mejor mantenerse alejado de los borradores para C ++ 0x, ya que los cambios allí son mucho más extensos)

Aparte de eso, cada implementación de la biblioteca estándar es necesaria para documentar una gran cantidad de detalles (comportamiento definido por la implementación, cosas que no están especificadas en el estándar, pero que se dejan al implementador de la biblioteca). Y, además, la mayoría de ellos también presentan una documentación detallada de toda la biblioteca.

Microsoft tiene documentación detallada disponible en MSDN . La documentación respeta el estándar y marca claramente todas las extensiones no estándar para que sepa cuál es cuál.

SGI también tiene la documentación en línea (aunque es más antigua y, en algunos casos, no del todo precisa).

IBM tiene documentación similar disponible en su sitio web, y creo que GCC también lo hace.

Ciertamente espero que no haya una forma de acceder al contenedor subyacente de una cola de prioridad. Si pudiera, podría estropear la estructura interna del montón de la cola de prioridad. En cualquier caso, el objective de estos adaptadores es que solo presentan la interfaz mínima de la stack o cola, y abstraen todas las demás cosas. Entonces, si necesita usar alguna otra característica, debería haber usado el contenedor original directamente.

En cuanto a la documentación del STL, puede consultar la documentación del STL de SGI aquí . Hay algunas diferencias entre el STL de SGI y el estándar de C ++, pero en su mayoría se observan en ese sitio. Además, cppreference.com es una documentación wiki de la biblioteca C ++ que se está volviendo más completa.

Puede escribir una subclase para recuperar la variable miembro c. Vea este comentario de 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? * Presumbly 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; 

¿Dónde puedo encontrar la documentación oficial de la biblioteca estándar?

El estándar C ++ está disponible en tapa dura, ISBN 0470846747. Los borradores de Estándar están ampliamente disponibles en formato PDF, pero deberá tener cuidado de hacerlos coincidir con las versiones oficiales (C ++ 98,03,11 o 14). Los borradores actuales superan el estándar C ++ 14.