File: call_if_cxx14.cpp

package info (click to toggle)
boost1.90 1.90.0-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 593,120 kB
  • sloc: cpp: 4,190,908; xml: 196,648; python: 34,618; ansic: 23,145; asm: 5,468; sh: 3,774; makefile: 1,161; perl: 1,020; sql: 728; ruby: 676; yacc: 478; java: 77; lisp: 24; csh: 6
file content (92 lines) | stat: -rw-r--r-- 2,641 bytes parent folder | download | duplicates (16)
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
85
86
87
88
89
90
91
92

// Copyright (C) 2008-2018 Lorenzo Caminiti
// Distributed under the Boost Software License, Version 1.0 (see accompanying
// file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
// See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html

#include <boost/contract/call_if.hpp>
#include <type_traits>
#include <iterator>
#include <functional> // std::bind for generic lambdas.
#include <vector>
#include <list>
#include <sstream>

template<typename Iter>
struct is_random_access_iterator : std::is_same<
    typename std::iterator_traits<Iter>::iterator_category,
    std::random_access_iterator_tag
> {};

template<typename Iter>
struct is_bidirectional_iterator : std::is_same<
    typename std::iterator_traits<Iter>::iterator_category,
    std::bidirectional_iterator_tag
> {};

template<typename Iter>
struct is_input_iterator : std::is_same<
    typename std::iterator_traits<Iter>::iterator_category,
    std::input_iterator_tag
> {};

//[call_if_cxx14
template<typename Iter, typename Dist>
void myadvance(Iter& i, Dist n) {
    Iter* p = &i; // So captures change actual pointed iterator value.
    boost::contract::call_if<is_random_access_iterator<Iter> >(
        std::bind([] (auto p, auto n) { // C++14 generic lambda.
            *p += n;
        }, p, n)
    ).template else_if<is_bidirectional_iterator<Iter> >(
        std::bind([] (auto p, auto n) {
            if(n >= 0) while(n--) ++*p;
            else while(n++) --*p;
        }, p, n)
    ).template else_if<is_input_iterator<Iter> >(
        std::bind([] (auto p, auto n) {
            while(n--) ++*p;
        }, p, n)
    ).else_(
        std::bind([] (auto false_) {
            static_assert(false_, "requires at least input iterator");
        }, std::false_type()) // Use constexpr value.
    );
}
//]

struct x {}; // Test not an iterator (static_assert failure in else_ above).

namespace std {
    template<>
    struct iterator_traits<x> {
        typedef void iterator_category;
    };
}

int main() {
    std::vector<char> v;
    v.push_back('a');
    v.push_back('b');
    v.push_back('c');
    v.push_back('d');
    std::vector<char>::iterator r = v.begin(); // Random iterator.
    myadvance(r, 1);
    assert(*r == 'b');

    std::list<char> l(v.begin(), v.end());
    std::list<char>::iterator b = l.begin(); // Bidirectional iterator.
    myadvance(b, 2);
    assert(*b == 'c');

    std::istringstream s("a b c d");
    std::istream_iterator<char> i(s);
    myadvance(i, 3);
    assert(*i == 'd');

    // x j;
    // myadvance(j, 0); // Error (correctly because x not even input iter).

    return 0;
}