Получить тип контейнера из его итератора в С++ (STL)

Легко дать контейнеру получить связанные итераторы, например:

std::vector<double>::iterator i; //An iterator to a std::vector<double>

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

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

ContainerOf< std::vector<double>::iterator >::type 

оценивается как

std::vector<double>

Возможно ли это? Если нет, то почему?

Заранее благодарю за помощь!

Ответы

Ответ 1

Я не думаю, что это было бы возможно. В некоторых библиотеках STL у вас фактически есть векторный итератор как тип указателя, i.e. std::vector<T>::iterator is a T*, поэтому я не могу представить, каким образом вы могли бы вернуться к типу контейнера из этого.

Ответ 2

Просто для удовольствия, вот что-то, что я быстро взломал с помощью Boost.MPL(предупреждение: это было проверено наглядно, поэтому обращайтесь с осторожностью):

#include <boost/mpl/list.hpp>
#include <boost/mpl/find_if.hpp>
#include <boost/type_traits.hpp>
#include <vector>
#include <string>
#include <list>
#include <set>

// List of candidate container types
template<typename T>
struct ContainersOf : boost::mpl::list<
    std::vector<T>,
    std::basic_string<T>,
    std::list<T>,
    std::set<T>
>{};

// Metafunction to evaluate if IteratorT == ContainerT::iterator
template<class IteratorT, class ContainerT>
struct IsIteratorOf
{
    typedef typename 
    boost::is_same<
        IteratorT, 
        typename ContainerT::iterator
    >::type type;
};

// Metafunction to compute a container type from an iterator type
template<class IteratorT>
struct ContainerOf
{
    typedef typename 
    boost::mpl::deref<typename 
        boost::mpl::find_if<
            ContainersOf<typename std::iterator_traits<IteratorT>::value_type>,
            IsIteratorOf<IteratorT, boost::mpl::_1>
        >::type
    >::type type;
};

// Test
int main()
{
    ContainerOf<std::list<int>::iterator>::type l;
    std::list<int> l2 = l;  // OK
    std::vector<int> v = l; // Fails to compile

    return 0;
}

Ответ 3

Точные типы времени исполнения итераторов С++ STL намеренно undefined и, следовательно, специфичны для реализации. Вы можете выполнить поиск в файлах заголовков компилятора, чтобы узнать, какой тип фактически используется, и вывести из него контейнер, но он зависит от производителя и версии, поэтому он подвержен взлому.

Ответ 4

Точка итераторов состоит в том, что вы используете их для выполнения работы, не зная тип базового контейнера, например, передавая пару "начало/конец" и выполняющую работу в этом диапазоне.

Однако, если все, о чем вы заботитесь, это тип итератора, я считаю, что вы можете использовать свойства итератора, чтобы определить, например, если итератор является произвольным доступом. Возьмите std::advance, общий случай состоит в том, что он вызывает operator++ в итераторе n раз, но специализирован для итераторов с произвольным доступом, чтобы использовать + = вместо.

Кроме этого, я не знаю, как получить тип контейнера из итератора.