I am trying to implement a custom std compliant container class with an iterator.
To do so, i started to define the public type definitions to be used by traits for the container class as well as the iterator.
I want to make it c++17 compliant and try to not use c++20 removed features or c++17 deprecated.
This is what i got:
template <typename T, typename Alloc = std::allocator<T>>
class container {
using allocator_type = Alloc;
using value_type = std::allocator_traits<Alloc>::value_type;
using pointer = std::allocator_traits<Alloc>::pointer;
using const_pointer = std::allocator_traits<Alloc>::const_pointer;
using reference = value_type&; // <-- here
using const_reference = const value_type&; // <-- here
using difference_type = std::allocator_traits<Alloc>::difference_type;
using size_type = std::allocator_traits<Alloc>::size_type;
class iterator;
};
template <typename T, typename Alloc = std::allocator<T>>
class container::iterator {
using value_type = std::allocator_traits<Alloc>::value_type;
using pointer = std::allocator_traits<Alloc>::pointer;
using const_pointer = std::allocator_traits<Alloc>::const_pointer;
using reference = value_type&; // <-- here
using const_reference = const value_type&; // <-- here
using difference_type = std::allocator_traits<Alloc>::difference_type;
using size_type = std::allocator_traits<Alloc>::size_type;
};
Do i have to define reference and const_reference types myself like i did in the example or is there another std way of doint it?
Another question would be how to define a const_iterator without duplicating my iterator.
Some say that i should template my iterator with the value type, some just write a new iterator.
If i would template i dont know how i would create the right type traits for it, so my function definitions for the std:
reference operator*() const
and pointer operator->() const
,
because reference
would be const_reference
and const_reference
would be technically const const_reference
.
For example:
template <typename T>
class container {
template <typename ValueType>
class iterator;
using iterator = iterator<T>;
using const_iterator = iterator<const T>;
};
template <typename ValueType>
class container::iterator {
public:
using value_type = ValueType;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
reference operator*() const;
pointer operator->() const;
};
Do i have to define reference and const_reference types myself like i did in the example
Yes. The allocator doesn't know how your container is implemented, so it cannot know how to define those type aliases.
Another question would be how to define a const_iterator without duplicating my iterator.
With the magic of templates. iterator<T>
vs iterator<const T>
.
because reference would be const_reference and const_reference would be technically const const_reference
That's not a problem as long as const_reference
is const T&
because due to const folding rules const const_reference
is simply const T&
which is what you would want.