Шаблонный класс с итератором в контейнер STL - PullRequest
0 голосов
/ 10 октября 2018

Я хочу создать шаблонный класс, в котором в качестве члена используется итератор контейнера STL.Вот как далеко я ушел:

#include <iostream>
#include <vector>

using namespace std;

template<typename Element, template <class> class StdLibContainer>
struct ClassHoldingAnIteratorToAStandardContainer
{
    ClassHoldingAnIteratorToAStandardContainer(){}
    typename StdLibContainer<Element*>::iterator std_lib_iterator;
};


int main()
{
    vector<int> vec{1,2,3};
    ClassHoldingAnIteratorToAStandardContainer<int,vector<int>> holding_iterator_to_vec;
    //DOES NOT WORK, compiler says: expected a class template, got ‘std::vector<int>’
    return 0;
}
  1. Не могли бы вы объяснить синтаксис template <typename> class StdLibContainer?Я нашел это где-то на stackoverflow.Но я не понимаю этого.

  2. Как я могу создать экземпляр ClassHoldingAnIteratorToAStandardContainer?Все мои попытки пока не увенчались успехом.Компилятор всегда выдает сообщение об ошибке: `ожидал шаблон класса, получил 'std :: vector'

В приведенном выше примере я хочу назначить holding_iterator_to_vec vec.begin().

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Если вам действительно не нужно знать тип контейнера, я настоятельно рекомендую сохранить ваш ClassHoldingAnIteratorToAStandardContainer независимо от типа конкретного контейнера.Если вам просто нужен итератор, это проще и достаточно:

template<typename iterator>
struct iterator_wrapper {
    iterator iter;    
};

Это минимум, необходимый для того, чтобы иметь итератор в качестве члена :).

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

#include <iterator>
#include <vector>
#include <iostream>

template<typename iterator>
struct iterator_wrapper {
    using value_type = typename std::iterator_traits<iterator>::value_type;
    iterator iter;    
    bool operator!=(const iterator& other) { return iter != other;}
    iterator_wrapper& operator++(){ 
        ++iter;
        return *this;
    }
    const value_type& operator*() { return *iter; }
};

template <typename iterator>
iterator_wrapper<iterator> wrap_iterator(iterator it) { 
    return {it}; 
}

int main() {
    std::vector<int> vec{1,2,3};
    auto it = wrap_iterator(vec.begin());    
    for (;it != vec.end();++it) std::cout << *it;       

}

Также есть проблема в вашем коде.

typename StdLibContainer<Element*>::iterator

для контейнеров указателей, в то время как в основном у вас есть int s.Если вы хотите вывести тип итератора из типа контейнера, вы можете сделать это, например, следующим образом:

template <typename container, 
          typename iterator = typename container::iterator>
iterator_wrapper<iterator> wrap_begin(container& c) { 
    return {c.begin()}; 
}

, что упрощает создание iterator_wrapper, например

auto x = wrap_begin(vec);

Обратите внимание, что этот ответ относится к C ++ 11, в более новых стандартах есть руководства по выводам, которые делают такие make_x методы более или менее излишними.

0 голосов
/ 10 октября 2018

template <typename> class совпадает с template <class> class.Первоначально, когда были введены шаблоны, они допускали две эквивалентные формы:

template<class T> struct Foo {};
// or
template<typename T> struct Foo {};

Не спрашивайте меня, почему!Однако это не относится к параметрам шаблона:

template <template <class> typename T> struct Foo {};

был единственным допустимым синтаксисом.Видимо, люди были недовольны этим, поэтому синтаксис был смягчен.

Что касается вашего второго вопроса, std::vector принимает как минимум два аргумента шаблона, тип данных и распределитель.Вот почему шаблон с одним аргументом не обрезает его до C ++ 17.После C ++ 17 он будет работать.

Чтобы сделать его универсальным, используйте

template<template <class...> class Container> struct Foo{};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...