2010-06-10 2 views
15

Легко дается контейнер, чтобы получить связанные итераторы, например:Получить тип контейнера из (его) типа итератора в C++ (STL)

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

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

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

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

вычисляет

std::vector<double> 

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

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

+2

Вы пытаетесь узнать о Concep итератора ? то есть, если это случайный доступ? STL использует теги для этого. Обычно нет причин знать, откуда итератор. – pmr

+0

Знаете ли вы, есть ли у вас итератор в одном из 7 контейнеров STL, или вам нужно предложение «else»? – MSalters

ответ

7

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

+0

Однако это не может быть итератором любого другого контейнера STL. Их всего 7, и вы можете их уничтожить. – MSalters

+0

Это справедливый вопрос. Как насчет разницы между картой и мультимапом? Можете ли вы рассказать им отдельно от оператора сравнения? – Hitobat

+0

Это может быть возможно, если структура 'std :: iterator_traits ' haves 'typedef T container_type;' однако вы можете создать свой собственный 'std :: iterator_traits_pro' с таким typedef. – k06a

0

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

+0

Спасибо за ответ! Я теперь ошибаюсь, что моя проблема намеренно не «разрешима». – stepelu

0

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

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

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

+0

Это достигается посредством отправки тегов. http://www.boost.org/community/generic_programming.html#tag_dispatching –

5

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

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

Большое спасибо за ваш ответ, однако ваше решение требует «специализации» к типам контейнеров, см. ContainerOf. – stepelu

Смежные вопросы