0

I want to create a template class which has an iterator of a STL container as a member. That is how far I got:

#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. Could you explain the syntax template <typename> class StdLibContainer? I found it somewhere on stackoverflow. BUt I don't understand it.

  2. How can I create an instance of ClassHoldingAnIteratorToAStandardContainer ? All my attempts failed so far. The compiler always gives the error message: `expected a class template, got ‘std::vector’

In the above example i want to assign holding_iterator_to_vec vec.begin().

newandlost
  • 935
  • 2
  • 10
  • 21
  • 1
    That's a [template template parameter](https://en.cppreference.com/w/cpp/language/template_parameters#Template_template_parameter). It requires a template instead of a type as argument. – François Andrieux Oct 10 '18 at 18:24
  • @πάντα ῥεῖ That question has nothing to do with template template parameters. It's one of the cases for `typename` that isn't mentioned in the answers. – François Andrieux Oct 10 '18 at 18:28
  • @FrançoisAndrieux Okeh sorry, I was to fast here. Sounded so at a 1st glance. – πάντα ῥεῖ Oct 10 '18 at 18:29
  • @newandlost What's the problem you actually want to solve doing this? It sounds somehow weird, and I have doubts if there are better designs to achieve what you're actually want to do. XY problem? – πάντα ῥεῖ Oct 10 '18 at 18:33
  • do you need to know the type of the container? Why not just have the type of the iterator as template parameter? – 463035818_is_not_an_ai Oct 10 '18 at 18:36
  • @πάνταῥεῖ I have a class, that has e.g. int A, int B, and a stl container like vector C_to_Z as member variable. In the end I want to create a custom iterator, that goes A,B and then uses the iterator of the vector to go C to Z. – newandlost Oct 11 '18 at 13:03

2 Answers2

1

template <typename> class is the same as template <class> class. Originally, when templates were introduced, they allowed two equivalent forms:

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

Do not ask me why! However, the same was not true for template template parameters:

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

was the only allowed syntax. Apparently, people were unhappy about it, so the syntax was relaxed.

As for your second question, std::vector takes at least two template arguments, data type and allocator. This is why a single argument template doesn't cut it before C++17. After C++17, it would work.

To make it universal, use

template<template <class...> class Container> struct Foo{};
SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • 1
    Since C++17 `template class` can actually match `std::vector` (because the second template parameter has a default value). – HolyBlackCat Oct 10 '18 at 18:38
  • 1
    @HolyBlackCat that's something I am not aware of! Do you have a link (or a name of the feature I can search for)? – SergeyA Oct 10 '18 at 18:39
  • 2
    Here's a revelant [defect report](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#150). And [this page](https://en.cppreference.com/w/cpp/language/template_parameters) has an example demonstrating this change (Ctrl+F `CWG 150`). – HolyBlackCat Oct 10 '18 at 18:45
  • only the `...` in `` are for a pack the others are just "`etc...`" right? – 463035818_is_not_an_ai Oct 10 '18 at 18:54
  • @user463035818 Yup. – HolyBlackCat Oct 10 '18 at 18:57
  • well actually there was a hidden "can you please make it more clear" in my comment ;). I tried to make it less ambiguous. Hope i didnt put anything wrong, just roll back if you dont like it – 463035818_is_not_an_ai Oct 10 '18 at 19:00
  • @HolyBlackCat much appreciated! – SergeyA Oct 10 '18 at 19:03
  • was sure if the correct "old" syntax was ` – 463035818_is_not_an_ai Oct 10 '18 at 19:06
  • @user463035818 that's why I put `...` - to make it cut both ways - but I realize it could be too confusing. I think, it's better this way. And yes, I'd be curious to know the rationale too. I'd ask a question, but I am afraid it would be downvoted to minus infinity. – SergeyA Oct 10 '18 at 19:09
  • I was going to write a question, but then I found [this](https://stackoverflow.com/a/213135/4117728) which has half of the answer. For the other half my guess is that template template parameters came after the comitee decided to use `typename` rather than `class` for clarity (and keep allowing `class` for backward compatibility for normal tempalte parameters) and saw no obvious reason to allow `class` also there – 463035818_is_not_an_ai Oct 10 '18 at 19:38
  • My compiler only accepts `template – newandlost Oct 16 '18 at 12:28
  • And what is the correct syntax for initializing `ClassHoldingAnIteratorToAStandardContainer` ? I got a little bit confused. – newandlost Oct 16 '18 at 12:29
  • `ClassHoldingAnIteratorToAStandardContainer>> holding_iterator_to_vec;` dos not work... – newandlost Oct 16 '18 at 12:39
0

Unless you really need to know the type of the container, I would strongly recommend to keep your ClassHoldingAnIteratorToAStandardContainer independent of the concrete container type. If you just need the iterator, this is simpler and sufficient:

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

Thats the minimum you need to have an iterator as member :).

I dont really know what you want to use the iterator for, so just for the sake of an example lets add methods that actually use the iterator....

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

}

Also there is a problem in your code.

typename StdLibContainer<Element*>::iterator

is for containers of pointers while in main you have ints. If you want to infer the iterator type from the container type then you can do it for example like this:

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

which makes creating an iterator_wrapper as simple as

auto x = wrap_begin(vec);

Note that this answer applies to C++11, in newer standards there are deduction guides that make such make_x methods more or less superfluous afaik.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • Thanks, that sounds good. My usecase is the following: I hvae a Container that could in principle be e.g. a std::vector. But always when an element is insterted a want that this new element is registerd also somewhere else. So I created a custom ElementContainer, with a insert function that inserts a element into the vector and additionally executes the function. But I still want to be able to iterate over ElementContainer as I could do over std::vector. That is why the ElementContainer needs an iterator that basically wraps the iterator of vector. – newandlost Oct 16 '18 at 13:13
  • How could I incorporate `Element * operator->() const;` in your solution? – newandlost Oct 16 '18 at 13:15
  • @newandlost I updated the example to include an `operator*()const` , `operator->()const` is similar – 463035818_is_not_an_ai Oct 16 '18 at 17:13