C++ templates, default argument as a method - c++

For this implementation of selection sort:
template <typename Iterator, typename Compare>
void sort(Iterator begin, Iterator end, Compare comp) {
for (auto i = begin; i != end; ++i) {
auto min = i;
for (auto j = i + 1; j != end; ++j) {
if (comp(*j, *min)) {
min = j;
}
}
std::swap(*min, *i);
}
}
How should I modify it so that Compare comp should be std::less method if last parameter is skipped for sort method?
I tried function overloading by introducing another method:
template <typename Iterator>
void sort(Iterator begin, Iterator end) {
sort(begin, end, std::less<std::iterator_traits<Iterator>::value_type>());
}
But it gave errors like:
In file included from ../src/selection_sort_demo.cpp:1:
../include/selection_sort.hpp:24:29: error: template argument for template type parameter must be a type; did you forget 'typename'?
sort(begin, end, std::less<std::iterator_traits<Iterator>::value_type>());
^
typename
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/bits/stl_function.h:380:21: note: template parameter is declared here
template<typename _Tp>
^
In file included from ../src/selection_sort_demo.cpp:1:
../include/selection_sort.hpp:24:2: error: call to 'sort' is ambiguous
sort(begin, end, std::less<std::iterator_traits<Iterator>::value_type>());
^~~~
../src/selection_sort_demo.cpp:22:13: note: in instantiation of function template specialization 'selection::sort<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > >' requested here
selection::sort(v.begin(), v.end());
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/bits/stl_algo.h:4727:5: note: candidate function [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, _Compare = std::less<int>]
sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
^
../include/selection_sort.hpp:7:6: note: candidate function [with Iterator = __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, Compare = std::less<int>]
void sort(Iterator begin, Iterator end, Compare comp)
^
2 errors generated.
[2/4] Compiling cpp object 'test/testexe#exe/selection_sort_test.cpp.o'
FAILED: test/testexe#exe/selection_sort_test.cpp.o
clang++ '-Itest/testexe#exe' '-Itest' '-I../test' '-I../include' '-Wall' '-Winvalid-pch' '-Wnon-virtual-dtor' '-std=c++14' '-O0' '-g' '-pthread' '-MMD' '-MQ' 'test/testexe#exe/selection_sort_test.cpp.o' '-MF' 'test/testexe#exe/selection_sort_test.cpp.o.d' -o 'test/testexe#exe/selection_sort_test.cpp.o' -c ../test/selection_sort_test.cpp
In file included from ../test/selection_sort_test.cpp:2:
../include/selection_sort.hpp:24:29: error: template argument for template type parameter must be a type; did you forget 'typename'?
sort(begin, end, std::less<std::iterator_traits<Iterator>::value_type>());
^
typename
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/bits/stl_function.h:380:21: note: template parameter is declared here
template<typename _Tp>
^
In file included from ../test/selection_sort_test.cpp:2:
../include/selection_sort.hpp:24:2: error: call to 'sort' is ambiguous
sort(begin, end, std::less<std::iterator_traits<Iterator>::value_type>());
^~~~
../test/selection_sort_test.cpp:17:13: note: in instantiation of function template specialization 'selection::sort<__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > >' requested here
selection::sort(v1.begin(), v1.end());
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/bits/stl_algo.h:4727:5: note: candidate function [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, _Compare = std::less<int>]
sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
^
../include/selection_sort.hpp:7:6: note: candidate function [with Iterator = __gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >, Compare = std::less<int>]
void sort(Iterator begin, Iterator end, Compare comp)
^
2 errors generated.

Since it's c++14:
template <typename Iterator, typename Compare = std::less<> >
void sort(Iterator begin, Iterator end, Compare comp = Compare())
{
for (auto i = begin; i != end; ++i) {
auto min = i;
for (auto j = i + 1; j != end; ++j) {
if (comp(*j, *min)) {
min = j;
}
}
std::swap(*min, *i);
}
}
c++11:
template <typename Iterator, typename Compare = std::less< typename std::iterator_traits<Iterator>::value_type > >
void sort(Iterator begin, Iterator end, Compare comp = Compare())
{
for (auto i = begin; i != end; ++i) {
auto min = i;
for (auto j = i + 1; j != end; ++j) {
if (comp(*j, *min)) {
min = j;
}
}
std::swap(*min, *i);
}
}
Explanation:
We have to offer the compiler both a default type in the template argument list and a default function argument list.
For explanation of std::less<> since c++14 see:
http://en.cppreference.com/w/cpp/utility/functional/less

You were right, but forgot the typename keyword. Check this:
template <typename Iterator>
void sort(Iterator begin, Iterator end) {
sort(begin, end, std::less<typename std::iterator_traits<Iterator>::value_type>());
}
Probably you wanted default template argument, but this works too.

Related

Template Deduction Problem when adding equivalence check in std::enable_if

I am trying to benchmark different ways to sum. I'd like using an interface as follows
avx2_sum<sum_algorithm::normal>(container.begin(), container.end());
However, my attempt
enum class sum_algorithm: char{
normal,
kahan,
twofold_fast //https://arxiv.org/pdf/1401.0248.pdf
};
template<sum_algorithm algorithm_t, typename iterator_t, typename sum_t = typename std::iterator_traits<iterator_t>::value_type,
std::enable_if_t<std::is_same<sum_t, double>::value && (algorithm_t == sum_algorithm::normal)> = true>
sum_t avx2_sum(const iterator_t begin, const iterator_t end) noexcept {
// SIMD-parallel summation stage
auto running_sums = _mm256_set1_pd(0);
auto iterator_skip = 256/sizeof(sum_t);
for (iterator_t it = begin; it + iterator_skip < end; it += iterator_skip){
//TODO: flip to double load reduction
running_sums = _mm256_add_pd(_mm256_load_pd(it), running_sums);
}
// Serial summation
running_sums = _mm256_hadd_pd(running_sums, running_sums);
running_sums = _mm256_hadd_pd(running_sums, running_sums);
return _mm256_cvtsd_f64(running_sums);
}
produces the following:
error: no matching function for call to 'avx2_sum'
std::cout << "avx2<float, normal>: " << accumulators::avx2_sum<algo::normal>(float_arr.begin(), float_arr.end()) <<"\n";
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/rlfactory/dev/thommmj1/cppbenchmarks/cpp_utils/algorithms/cpu_accumulators.hpp:55:11: note: candidate template ignored: requirement 'std::is_same<float, double>::value' was not satisfied [with algorithm_t = accumulators::sum_algorithm::normal, iterator_t = __gnu_cxx::__normal_iterator<float *, std::vector<float, std::allocator<float> > >, sum_t = float]
sum_t avx2_sum(const iterator_t begin, const iterator_t end) noexcept {
^
/home/rlfactory/dev/thommmj1/cppbenchmarks/cpp_utils/algorithms/cpu_accumulators.hpp:71:11: note: candidate template ignored: substitution failure [with algorithm_t = accumulators::sum_algorithm::normal, iterator_t = __gnu_cxx::__normal_iterator<float *, std::vector<float, std::allocator<float> > >, sum_t = float]: a non-type template parameter cannot have type 'std::enable_if_t<std::is_same<float, float>::value && ((sum_algorithm)'\x00' == sum_algorithm::normal)>' (aka 'void')
sum_t avx2_sum(const iterator_t begin, const iterator_t end) noexcept {
^
/home/rlfactory/dev/thommmj1/cppbenchmarks/cpp_utils/algorithms/cpu_accumulators.hpp:87:11: note: candidate template ignored: requirement 'std::is_same<float, double>::value' was not satisfied [with algorithm_t = accumulators::sum_algorithm::normal, iterator_t = __gnu_cxx::__normal_iterator<float *, std::vector<float, std::allocator<float> > >, sum_t = float]
sum_t avx2_sum(const iterator_t begin, const iterator_t end) noexcept {
^
/home/rlfactory/dev/thommmj1/cppbenchmarks/cpp_utils/algorithms/cpu_accumulators.hpp:109:11: note: candidate template ignored: requirement 'std::is_same<float, float>::value && ((accumulators::sum_algorithm)'\x00' == sum_algorithm::kahan)' was not satisfied [with algorithm_t = accumulators::sum_algorithm::normal, iterator_t = __gnu_cxx::__normal_iterator<float *, std::vector<float, std::allocator<float> > >, sum_t = float]
sum_t avx2_sum(const iterator_t begin, const iterator_t end) noexcept {
I don't understand how deduction doesn't work here. Without the algorithm_t template portion and check, it works just fine. Perhaps it's due to my using statement? using algo = accumulators::sum_algorithm;

error: no type named 'type' while calling static function from a thread

Inside my generic Matrix(T) class I'm overloading operator+ using threading using a static function that adds to a single row like this:
template <class T>
static void addToRow(vector<T> &dest, const vector<T> &source, int pos, int colls)
{
typename vector<T>::iterator itDest = dest.begin() + pos;
typename vector<T>::iterator itSource = source.cend() + pos;
int counter = 0;
while (counter != colls)
{
*itDest++ += *itSource++;
++counter;
}
}
this function is implemented outside the class.
inside the operator+ overload I'm trying to call it like this:
const Matrix<T> operator+(const Matrix<T> &other) const
{
Matrix<T> result(*this);
vector<std::thread> threads;
int i, pos;
std::thread thrd;
for (i = 0; i < _rows; ++i)
{
pos = i*_colls;
threads.push_back(std::thread(&addToRow<T>, ref(_matrix), cref(other._matrix), pos, _colls));
}
typename vector<std::thread>::iterator it;
for (it = threads.begin(); it != threads.end(); ++it)
{
it->join();
}
return result;
}
and for the line:
threads.push_back(std::thread(&addToRow<T>, std::ref(*this), _matrix, other._matrix, pos, _colls));
I get the error:
/cygdrive/c/Users/Roy/Desktop/semester s year 1/CPP/ex3/Matrix.hpp:201:102: required from 'const Matrix<T> Matrix<T>::operator+(const Matrix<T>&) const [with T = int]'
/cygdrive/c/Users/Roy/Desktop/semester s year 1/CPP/ex3/main.cpp:44:31: required from here
/usr/lib/gcc/x86_64-pc-cygwin/4.9.3/include/c++/functional:1665:61: error: no type named 'type' in 'class std::result_of<void (*(const Matrix<int>*, std::vector<int, std::allocator<int> >, std::vector<int, std::allocator<int> >, int, int))(std::vector<int, std::allocator<int> >&, const std::vector<int, std::allocator<int> >&, int)>'
typedef typename result_of<_Callable(_Args...)>::type result_type;

Return an iterator inside a template

I'm trying to implement a simple template function, this code doesn't compile but I hope it will give you an idea about what I'm trying to do :
template<typename T>
typename T::iterator do_find(const T& container, const int val)
{
return std::find(container.begin(), container.end(), val);
}
I want to return the iterator that find itself returns, without knowing what type of container I receive in my template function do_find. What am I doing wrong ?
Here's the main :
int main()
{
std::vector<int> c;
c.push_back(42);
c.push_back(0);
c.push_back(1);
c.push_back(-58);
c.push_back(42);
c.push_back(777);
c.push_back(1911);
c.push_back(9);
do_find(c, 42);
return 0;
}
And the compiler error :
In file included from main.cpp:14:0:
find.hpp: In instantiation of ‘typename T::iterator do_find(const T&, int) [with T = std::vector<int>; typename T::iterator = __gnu_cxx::__normal_iterator<int*, std::vector<int> >]’:
main.cpp:29:16: required from here
find.hpp:17:59: error: could not convert ‘std::find<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, int>((& container)->std::vector<_Tp, _Alloc>::begin<int, std::allocator<int> >(), (& container)->std::vector<_Tp, _Alloc>::end<int, std::allocator<int> >(), (* & val))’ from ‘__gnu_cxx::__normal_iterator<const int*, std::vector<int> >’ to ‘std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}’
find.hpp: In function ‘typename T::iterator do_find(const T&, int) [with T = std::vector<int>; typename T::iterator = __gnu_cxx::__normal_iterator<int*, std::vector<int> >]’:
find.hpp:18:1: error: control reaches end of non-void function [-Werror=return-type]
cc1plus: all warnings being treated as errors
If you have const T& container as your first parameter to this function, you have to return typename T::const_iterator instead.

Checking for list membership using the STL and a unary function adapted functor

I've attempted to write a brief utility functor that takes two std::pair items and tests for their equality, but disregarding the ordering of the elements. Additionally (and this is where I run into trouble) I've written a function to take a container of those std::pair items and test for membership of a given pair argument in a the container.
/* A quick functor way to check the identity of the two items of a pair to see if each pair contains the same items regardless of order */
template <class T>
class EqualPairs : public std::binary_function<T,T,bool> {
T arg2;
public:
explicit EqualPairs (const T& x) : arg2(x) { }
bool operator() (const T& arg1) {
bool same = false;
if (arg1 == arg2 || (arg1.first == arg2.second && arg1.second == arg2.first))
same = true;
return same;
}
};
/* checks to see if the give pair p is a member of the list of pairs l. The pairs are compared disregarding the order of the pair elements (i.e. (4,2) == (2,4)) */
template <class P>
bool PairListMember (const P& p, const std::vector<P>& l)
{
std::vector<P>::iterator it;
it = find_if (l.begin(), l.end(), EqualPairs<P>(p));
bool member_of_list = (it != l.end()) ? true : false;
return member_of_list;
}
I couldn't think of a clean way to allow for generic container selection, so I hard-coded a std::vector as the container type, for now. Help on making the container type generic would also be appreciated, but for now I'd just like to get the above to compile and work. The error I get is:
In function ‘bool PairListMember(const P&, const std::vector<P, std::allocator<_CharT> >&)’:
error: expected `;' before ‘it’
error: ‘it’ was not declared in this scope
In function ‘bool PairListMember(const P&, const std::vector<P, std::allocator<_CharT> >&) [with P = std::pair<int, int>]’:
error: dependent-name ‘std::vector<P,std::allocator<_CharT> >::iterator’ is parsed as a non-type, but instantiation yields a type
note: say ‘typename std::vector<P,std::allocator<_CharT> >::iterator’ if a type is meant
changing the code by adding a 'typename' as suggested only results in the following errors:
error: no match for ‘operator=’ in ‘it = std::find_if [with _InputIterator = __gnu_cxx::__normal_iterator<const std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >, _Predicate = EqualPairs<std::pair<int, int> >](((const std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >*)l)->std::vector<_Tp, _Alloc>::begin [with _Tp = std::pair<int, int>, _Alloc = std::allocator<std::pair<int, int> >](), ((const std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >*)l)->std::vector<_Tp, _Alloc>::end [with _Tp = std::pair<int, int>, _Alloc = std::allocator<std::pair<int, int> >](), EqualPairs<std::pair<int, int> >(((const std::pair<int, int>&)((const std::pair<int, int>*)p))))’
/usr/include/c++/4.2/bits/stl_iterator.h:637: note: candidates are: __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >& __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >::operator=(const __gnu_cxx::__normal_iterator<std::pair<int, int>*, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > > >&)
For your compiler error, you need to use the typename keyword.
typename std::vector<P>::iterator it;
iterator is a typename, i.e. it refers to an embedded type within std::vector. When you access a typename with the :: operator within a template, you need to use the typename keyword so the compiler knows it is the name of a type, as opposed to the name of some variable or function within the class.
Edit: Also, you need to use a const_iterator, because your vector is const in this case.
typename std::vector<P>::const_iterator it;
There are a couple of issues with your EqualPairs template. It derives from binary_function but isn't actually a binary_function because operator() only takes one argument. You can (and should) make operator() const as it doesn't modify the EqualPairs object.
I think that you can simplify it somewhat.
template<class T>
struct EqualPairs : public std::binary_function<T, T, bool>
{
bool operator()(const T& lhs, const T& rhs) const
{
return lhs == rhs || lhs.first == rhs.second && lhs.second == rhs.first;
}
};
Then you can use std::bind1st (or std::bind2nd) to make a predicate out of your binary function and the input parameter. Also, by making the function a 'one liner' you don't actually need to declare a temporary variable for the iterator, so getting const and typename correct isn't an issue.
template <class P>
bool PairListMember (const P& p, const std::vector<P>& l)
{
return l.end() != std::find_if(l.begin(), l.end(), std::bind1st(EqualPairs<P>(), p));
}
You can make this template more generic by taking an iterator type as a template parameter. This removes your dependency on std::vector.
template <class Iter>
bool PairListMember(const typename std::iterator_traits<Iter>::value_type& p, Iter first, Iter last)
{
return last != std::find_if(first, last, std::bind1st(EqualPairs<typename std::iterator_traits<Iter>::value_type>(), p));
}

Why doesn't my custom iterator work with the STL copy?

I wrote an OutputIterator for an answer to another question. Here it is:
#include <queue>
using namespace std;
template< typename T, typename U >
class queue_inserter {
queue<T, U> &qu;
public:
queue_inserter(queue<T,U> &q) : qu(q) { }
queue_inserter<T,U> operator ++ (int) { return *this; }
queue_inserter<T,U> operator * () { return *this; }
void operator = (const T &val) { qu.push(val); }
};
template< typename T, typename U >
queue_inserter<T,U> make_queue_inserter(queue<T,U> &q) {
return queue_inserter<T,U>(q);
}
This works great for this little copy function:
template<typename II, typename OI>
void mycopy(II b, II e, OI oi) {
while (b != e) { *oi++ = *b++; }
}
But it doesn't work at all for the STL copy from algorithms. Here are the wonderful C++ errors I get:
i.cpp:33: error: specialization of ‘template<class _Iterator> struct std::iterator_traits’ in different namespace
/usr/include/c++/4.0.0/bits/stl_iterator_base_types.h:127: error: from definition of ‘template<class _Iterator> struct std::iterator_traits’
/usr/include/c++/4.0.0/bits/stl_algobase.h: In function ‘_OI std::__copy_aux(_II, _II, _OI) [with _II = int*, _OI = queue_inserter<int, std::deque<int, std::allocator<int> > >]’:
/usr/include/c++/4.0.0/bits/stl_algobase.h:335: instantiated from ‘static _OI std::__copy_normal<true, false>::copy_n(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OI = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
/usr/include/c++/4.0.0/bits/stl_algobase.h:387: instantiated from ‘_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OutputIterator = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
i.cpp:53: instantiated from here
/usr/include/c++/4.0.0/bits/stl_algobase.h:310: error: no type named ‘value_type’ in ‘struct std::iterator_traits<queue_inserter<int, std::deque<int, std::allocator<int> > > >’
/usr/include/c++/4.0.0/bits/stl_algobase.h:315: error: no type named ‘value_type’ in ‘struct std::iterator_traits<queue_inserter<int, std::deque<int, std::allocator<int> > > >’
/usr/include/c++/4.0.0/bits/stl_algobase.h:315: error: ‘__value’ is not a member of ‘<declaration error>’
/usr/include/c++/4.0.0/bits/stl_algobase.h:335: instantiated from ‘static _OI std::__copy_normal<true, false>::copy_n(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OI = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
/usr/include/c++/4.0.0/bits/stl_algobase.h:387: instantiated from ‘_OutputIterator std::copy(_InputIterator, _InputIterator, _OutputIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, _OutputIterator = queue_inserter<int, std::deque<int, std::allocator<int> > >]’
i.cpp:53: instantiated from here
/usr/include/c++/4.0.0/bits/stl_algobase.h:317: error: ‘__simple’ is not a valid template argument for type ‘bool’ because it is a non-constant expression
/usr/include/c++/4.0.0/bits/stl_algobase.h:317: error: ‘copy’ is not a member of ‘<declaration error>’
Here is the driver:
int main() {
vector<int> v;
v.push_back( 1 );
v.push_back( 2 );
queue<int> q;
copy( v.begin(), v.end(), make_queue_inserter(q) );
while (q.size() > 0) {
cout << q.front() << endl;
q.pop();
}
}
Why in the world is it specializing iterator_traits. What's wrong with my iterator? Can't I just write my own simple iterators?
Your queue_inserter needs to be derived from std::iterator so that all the typedefs such as value_type are properly defined since these are used inside STL algorithms This definition works:
template< typename T, typename U >
class queue_inserter : public std::iterator<std::output_iterator_tag, T>{
queue<T, U> &qu;
public:
queue_inserter(queue<T,U> &q) : qu(q) { }
queue_inserter<T,U> operator ++ (int) { return *this; }
queue_inserter<T,U> operator ++ () { return *this; }
queue_inserter<T,U> operator * () { return *this; }
void operator = (const T &val) { qu.push(val); }
};
Derive it from std::iterator. If you are interested the Dr. Dobb's has an article about custom containers and iterators.
Your iterator doesn't meet the requirement for an 'assignable' type which is a requirement for an output iterator because it contains a reference and assignable types need to ensure that after t = u that t is equivalent to u.
You can provide a suitable specialization for iterator_traits for your iterator either by deriving from a specialization of std::iterator or by providing one explicitly.
namespace std
{
template<> struct iterator_traits<MyIterator>
{
typedef std::output_iterator_tag iterator_category;
typedef void value_type;
typedef void difference_type;
};
}
#include <queue>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
template< typename T, typename U >
class queue_inserter
{
queue<T, U> &qu;
public:
// for iterator_traits to refer
typedef output_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
queue_inserter(queue<T,U> &q) : qu(q) { }
queue_inserter<T,U>& operator ++ () { return *this; }
queue_inserter<T,U> operator * () { return *this; }
void operator = (const T &val) { qu.push(val); }
};
template< typename T, typename U >
queue_inserter<T,U> make_queue_inserter(queue<T,U> &q)
{
return queue_inserter<T,U>(q);
}
int main()
{
// uses initalizer list (C++0x), pass -std=c++0x to g++
vector<int> v({1, 2, 3});
queue<int, deque<int>> q;
copy(v.cbegin(), v.cend(), make_queue_inserter(q));
while (!q.empty())
{
cout << q.front() << endl;
q.pop();
}
}
This should do it with iterator_traits; a helper struct in <iterator> which defines all types an iterator should typically define. Functions in <algorithm>, refer to these types when required like iterator_traits<it>::iterator_category or say iterator_traits<it>::value_type, etc. Just defining them inside one's custom iterator would do the trick. This is the modern way of writing iterators, as opposed to the classical way of inheriting from std::iterator. Having a look at <iterator> reveals that even std::iterator defines these types i.e. iterator_category, difference_type, etc. This is the reason, when inherited from std::iterator, the derived iterator class gets these due to heredity.