Подтвердить что ты не робот

Есть ли способ доступа к базовому контейнеру контейнеров-контейнеров STL?

Существует ли стандартный способ доступа к базовому контейнеру stack, queue, priority_queue?

Я нашел метод под названием _Get_container() в VS2008 реализации stack и queue, но не для priority_queue! Я думаю, что это не стандарт.

Кроме того, я знаю, что это глупый вопрос! где я могу найти официальную документацию стандартной библиотеки?


Просто для уточнения, я не пытался испортить основной контейнер. Все, что я пытался сделать, это следующее:

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;

Надеюсь, вы видите, что _Get_container() не является стандартным, а для priority_queue в VS2008 не существует ни одного.

4b9b3361

Ответ 1

Я заметил следующее решение в Интернете, и я использую его в своих проектах:

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

Удачи:).

Ответ 2

Я упомянул об этом в комментарии, но, подумав, кажется, что это ОК. queue/stack/priority_queue (т.е. все классы адаптеров) имеют элемент protected c, который является базовым контейнером (см. раздел 23.2.2.4 ИСО/МЭК 14882: 2003) поэтому, если вы наследуете от любого из них, вы можете получить к нему доступ напрямую.

Я знаю, что типичная мудрость заключается в том, чтобы не наследовать из контейнеров STL из-за не виртуальных dtors, но этот случай является исключением. Цель состоит не в перегрузке функциональности, а в том, чтобы сделать небольшие расширения для интерфейса адаптера. Ниже приведен пример добавления возможности доступа к базовому контейнеру.

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

К сожалению, вам придется прибегнуть к типу-punning для "обновления" существующего std::queue<int> * до Adapter<std::queue<int> > * без кастомизации типа. Технически, это, вероятно, будет работать нормально... но я рекомендую против него:

    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        

Поэтому я бы рекомендовал использовать typedefs, чтобы упростить обмен между ними. (Также обратите внимание в моем примере, что вам нужно только изменить 1 строку, чтобы изменить ее с queue на stack из-за либерального использования typedef s).

Ответ 3

В соответствии с принятым ответом более общий подход:

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

Как я узнал из этого ответа, .*& на самом деле два оператора, где указатель, полученный из &hack::c (который имеет тип ADAPTER::container_type ADAPTER::*), является target или .* для извлечения самого базового контейнера. hack имеет доступ к защищенному элементу, но после получения указателя средства защиты теряются. Таким образом, допустимо a.*(&hack::c).

Ответ 4

Нет, нет стандартного способа сделать это. Что касается доступа к стандарту, он недоступен в Интернете, вам нужно купить копию! Однако существуют различные копии черновиков доступен здесь.

Ответ 5

Эта страница SGI является самой "официальной" документацией, доступной в Интернете, я полагаю.

Причина, по которой вы не можете получить прямой доступ к базовому контейнеру, заключается в том, что адаптер изменяет шаблон использования, и наличие методов доступного контейнера будет нарушать этот новый шаблон использования. Например:

2 Это ограничение - единственная причина, по которой очередь существует вообще. В качестве очереди можно использовать любой контейнер, который представляет собой как переднюю последовательность вставки, так и последовательность обратной вставки; Например, у deque есть функции-члены front, back, push_front, push_back, pop_front и pop_back. Единственная причина использовать очередь контейнера-контейнера вместо детектора контейнера - это дать понять, что вы выполняете только операции с очередью, и никакие другие операции. http://www.sgi.com/tech/stl/queue.html

Если вы хотите обойти эту конструктивную особенность, вы можете сделать что-то вроде:

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

Ответ 6

Как правило, любой идентификатор, начинающийся с подчеркивания, является расширением поставщика или деталями реализации. Таким образом, _Get_container() - это просто дополнение, сделанное Microsoft, потому что оно упростило их реализацию. Он не предназначен для использования.

Что касается того, где найти документацию, он разбивается на несколько частей.

Авторитетным источником является, конечно же, языковой стандарт. Как сказал Нил Баттерворт, есть черновики, доступные для бесплатной онлайн-игры (которые по-прежнему очень полезны. Различия с окончательной версией на самом деле минимальны). Кроме того, вы можете купить копию. Он должен быть доступен из любой организации, представляющей ISO в вашей стране (и, возможно, из других источников). Документ, который вы ищете, ISO/IEC 14882:2003 Programming Language C++. (14882 - это стандартное число, 2003 год - год последней ревизии. Если вы столкнетесь с версией 1998 года, вы также можете использовать это. Различия действительно смехотворны между ними и в основном сводятся к нескольким разъяснениям. вероятно, лучше держаться подальше от черновиков для С++ 0x, так как изменения там гораздо более обширны)

Кроме того, каждая реализация стандартной библиотеки требуется для документирования большого количества деталей (поведение, определяемое реализацией, вещи, которые не указаны в стандарте, но оставлены до реализации библиотеки). Кроме того, большинство из них также выложили подробную документацию всей библиотеки.

Microsoft имеет подробную документацию, доступную на MSDN. Документация соответствует стандарту и четко обозначает все нестандартные расширения, чтобы вы знали, что именно.

SGI также имеет документацию онлайн (хотя она старше и в некоторых случаях не совсем точная).

IBM имеет аналогичную документацию на своем веб-сайте, и я считаю, что GCC тоже делает.

Ответ 7

Я, конечно, надеюсь, что нет доступа к базовому контейнеру очереди приоритетов. Если бы вы могли, вы могли бы испортить внутреннюю структуру кучи очереди приоритетов. В любом случае, точка этих адаптеров состоит в том, что они предоставляют вам минимальный интерфейс стека или очереди и абстрагируют все другие вещи. Поэтому, если вам нужно использовать любые другие функции, вы должны были использовать оригинальный контейнер напрямую.

Что касается документации STL, вы можете посмотреть документацию SGI STL здесь. Существует несколько различий между SGI STL и стандартом С++, но они в основном отмечены на этом сайте. Кроме того, cppreference.com является вики-документацией библиотеки С++, которая становится более полной.

Ответ 8

Вы можете написать подкласс для получения переменной-члена c. Смотрите этот комментарий от 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 protected instead
 *  of private: to allow derivation.  But none of the other
 *  containers allow for derivation.  Odd.)
 */
_Sequence c;

Ответ 9

Где я могу найти официальную документацию стандартной библиотеки?

Стандарт С++ доступен в твердом переплете, ISBN 0470846747. Черновики стандарта широко доступны в формате PDF, но вы должны быть осторожны, чтобы сопоставить их с официальными версиями (С++ 98,03,11 или 14). Текущие черновики превышают стандарт С++ 14.