1
2 // Copyright (C) 2008-2018 Lorenzo Caminiti
3 // Distributed under the Boost Software License, Version 1.0 (see accompanying
4 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
5 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
6
7 #include <boost/contract/call_if.hpp>
8 #include <type_traits>
9 #include <iterator>
10 #include <functional> // std::bind for generic lambdas.
11 #include <vector>
12 #include <list>
13 #include <sstream>
14
15 template<typename Iter>
16 struct is_random_access_iterator : std::is_same<
17 typename std::iterator_traits<Iter>::iterator_category,
18 std::random_access_iterator_tag
19 > {};
20
21 template<typename Iter>
22 struct is_bidirectional_iterator : std::is_same<
23 typename std::iterator_traits<Iter>::iterator_category,
24 std::bidirectional_iterator_tag
25 > {};
26
27 template<typename Iter>
28 struct is_input_iterator : std::is_same<
29 typename std::iterator_traits<Iter>::iterator_category,
30 std::input_iterator_tag
31 > {};
32
33 //[call_if_cxx14
34 template<typename Iter, typename Dist>
myadvance(Iter & i,Dist n)35 void myadvance(Iter& i, Dist n) {
36 Iter* p = &i; // So captures change actual pointed iterator value.
37 boost::contract::call_if<is_random_access_iterator<Iter> >(
38 std::bind([] (auto p, auto n) { // C++14 generic lambda.
39 *p += n;
40 }, p, n)
41 ).template else_if<is_bidirectional_iterator<Iter> >(
42 std::bind([] (auto p, auto n) {
43 if(n >= 0) while(n--) ++*p;
44 else while(n++) --*p;
45 }, p, n)
46 ).template else_if<is_input_iterator<Iter> >(
47 std::bind([] (auto p, auto n) {
48 while(n--) ++*p;
49 }, p, n)
50 ).else_(
51 std::bind([] (auto false_) {
52 static_assert(false_, "requires at least input iterator");
53 }, std::false_type()) // Use constexpr value.
54 );
55 }
56 //]
57
58 struct x {}; // Test not an iterator (static_assert failure in else_ above).
59
60 namespace std {
61 template<>
62 struct iterator_traits<x> {
63 typedef void iterator_category;
64 };
65 }
66
main()67 int main() {
68 std::vector<char> v;
69 v.push_back('a');
70 v.push_back('b');
71 v.push_back('c');
72 v.push_back('d');
73 std::vector<char>::iterator r = v.begin(); // Random iterator.
74 myadvance(r, 1);
75 assert(*r == 'b');
76
77 std::list<char> l(v.begin(), v.end());
78 std::list<char>::iterator b = l.begin(); // Bidirectional iterator.
79 myadvance(b, 2);
80 assert(*b == 'c');
81
82 std::istringstream s("a b c d");
83 std::istream_iterator<char> i(s);
84 myadvance(i, 3);
85 assert(*i == 'd');
86
87 // x j;
88 // myadvance(j, 0); // Error (correctly because x not even input iter).
89
90 return 0;
91 }
92
93