-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathiterator_traits.cc
84 lines (72 loc) · 2.82 KB
/
iterator_traits.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Implement traits-based function overload with type aliases.
#include <algorithm>
#include <forward_list>
#include <numeric>
#include <iterator>
#include <random>
#include <vector>
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest/doctest.h"
// Value_type is a type alias to the value_type for a container.
template <typename Cont>
using Value_type = typename Cont::value_type;
// Iterator_type is a type alias to the iterator type for a container.
template <typename Cont>
using Iterator_type = typename Cont::iterator;
// Iterator_category is a type alias to the iterator category.
template <typename Iter>
using Iterator_category = typename std::iterator_traits<Iter>::iterator_category;
// sort_helper sorts containers with random access.
template <typename RandomAccessIter>
void sort_helper(RandomAccessIter first, RandomAccessIter last, std::random_access_iterator_tag)
{
std::sort(first, last);
}
// sort_helper sorts containers with forward access.
template <typename ForwardIter>
void sort_helper(ForwardIter first, ForwardIter last, std::forward_iterator_tag)
{
// Copy elements to a container with random access.
std::vector<Value_type<ForwardIter>> v{first, last};
std::sort(std::begin(v), std::end(v));
// Overwrite elements with sorted copy.
std::copy(std::begin(v), std::end(v), first);
}
// sort uses tag dispatch to select from among the overloaded sort_helper functions.
template <typename Cont>
void sort(Cont& c)
{
using Iter = Iterator_type<Cont>; // Type of iterator.
sort_helper(std::begin(c), std::end(c), Iterator_category<Iter>{}); // Iterator_category<> gives tag.
}
TEST_CASE("[iterator_traits]")
{
std::default_random_engine gen{};
// Allocate vector of 1e3 elements in random order.
std::size_t nelems = 1'000;
std::vector<int> nums(nelems);
std::iota(std::begin(nums), std::end(nums), 1);
std::shuffle(std::begin(nums), std::end(nums), gen);
SUBCASE("std::vector")
{
// Confirm sort.
auto pre = std::is_sorted(std::begin(nums), std::end(nums));
REQUIRE(pre == false);
sort(nums); // Uses overload based on std::random_access_iterator_tag.
auto post = std::is_sorted(std::begin(nums), std::end(nums));
REQUIRE(post == true);
}
SUBCASE("std::forward_list")
{
// Copy vector to std::forward_list using std::front_inserter.
std::forward_list<int> nums_list;
std::copy(std::begin(nums), std::end(nums),
std::front_inserter(nums_list));
// Confirm sort.
auto pre = std::is_sorted(std::begin(nums_list), std::end(nums_list));
REQUIRE(pre == false);
sort(nums_list); // Uses overload based on std::forward_iterator_tag.
auto post = std::is_sorted(std::begin(nums_list), std::end(nums_list));
REQUIRE(post == true);
}
}