Search code examples
c++templatesiteratorcontainers

How to obtain iterator type from template parameter, if template parameter is a reference type


The question title may not be super clear, but hopefully the below explains what is my problem.

Let's say I have the following (simplified) class template:

template <typename T, typename Container = std::vector<T>>
class MyVector {
  using iterator = typename Container::iterator;
    
  Container data{};

public:
  MyVector(initializer_list<T> l) : data(l) {}
  iterator begin() { return data.begin(); }
};

If I create an object like MyVector<int> vec {1, 2, 3}; it works fine.

However, if I try to create an object like MyVector<int, std::vector<int>&> vec; (note the &), then in the iterator type definition I get the error:

Type 'std::vector<int> &' cannot be used prior to '::' because it has no members

I tried exploring std::remove_reference and changed the line to:

using iterator = typename std::remove_reference<Container>::type::iterator;

but this also doesn't work - the error I get in this case is:

No type named 'iterator' in 'std::remove_reference<std::vector<int>>'

What I would like to achieve is to have a type definition (for iterator) that works if Container is a std::vector<T> as well as a reference to std::vector<T> (or whatever Container type is used, e.g. std::array - which means I cannot simply use std::vector<T>::iterator in the typedef).

Is there any way to achieve this?


Solution

  • The std::remove_reference will work here. Or you need std::remove_reference_t version of it

    using iterator = std::remove_reference_t<Container>::iterator;
    //                             ^^^^^^^^^^^^
    

    That is mean, if you do not have access to the , provide a type alias for this

    template< class T >
    using remove_reference_t = typename remove_reference<T>::type;
    

    Also note that, in order to work with

    MyVector<int, std::vector<int>&> vec(v);
    //                              ^^^^^^^^ --> not an ini-list
    

    class MyVector must have a constructor

    MyVector(Container c) : data(c) {} 
    

    The std::initializer_list will not work with reference qualified container type.

    Here is the demo