1. 程式人生 > >《STL原始碼剖析》筆記-配接器adapters

《STL原始碼剖析》筆記-配接器adapters

配接器adapters在STL中起到轉換、連線的作用,包括仿函式配接器(function adapter)、容器配接器(container adapter)、迭代器配接器(iterator adapter)。

容器配接器

迭代器配接器

STL提供的迭代器配接器包括insert iterators、reverse Iterators、iostream iterators。

insert iterators的作用是將一般迭代器的賦值操作轉變為插入操作,有back_insert_iterator、front_insert_iterator、insert_iterator三種,分別用於尾端插入、前端插入、指定位置插入。

// 模板引數為容器物件
template <class Container>
class back_insert_iterator {
protected:
    Container* container;
public:
    typedef output_iterator_tag iterator_category;
    typedef void                value_type;
    typedef void                difference_type;
    typedef void                pointer;
    typedef void                reference;

	// 繫結容器
    explicit back_insert_iterator(Container& x) : container(&x) {}

	// 過載=操作符,轉為呼叫push_back
    back_insert_iterator<Container>& operator=(const typename Container::value_type& value) {
        container->push_back(value);
        return *this;
    }
  
    // 遮蔽部分操作符
    back_insert_iterator<Container>& operator*() { return *this; }
    back_insert_iterator<Container>& operator++() { return *this; }
    back_insert_iterator<Container>& operator++(int) { return *this; }
};

// 輔助函式,便於呼叫
template <class Container>
inline back_insert_iterator<Container> back_inserter(Container& x) {
	  return back_insert_iterator<Container>(x);
}

template <class Container>
class front_insert_iterator {
protected:
    Container* container;
public:
    typedef output_iterator_tag iterator_category;
    typedef void                value_type;
    typedef void                difference_type;
    typedef void                pointer;
    typedef void                reference;

    explicit front_insert_iterator(Container& x) : container(&x) {}

	// 過載=操作符,轉為呼叫push_front
    front_insert_iterator<Container>&operator=(const typename Container::value_type& value) {
        container->push_front(value);
        return *this;
    }
    front_insert_iterator<Container>& operator*() { return *this; }
    front_insert_iterator<Container>& operator++() { return *this; }
    front_insert_iterator<Container>& operator++(int) { return *this; }
};

template <class Container>
inline front_insert_iterator<Container> front_inserter(Container& x) {
	return front_insert_iterator<Container>(x);
}

template <class Container>
class insert_iterator {
protected:
    Container* container;
    typename Container::iterator iter;
public:
    typedef output_iterator_tag iterator_category;
    typedef void                value_type;
    typedef void                difference_type;
    typedef void                pointer;
    typedef void                reference;

    insert_iterator(Container& x, typename Container::iterator i)
        : container(&x), iter(i) {}

	// 過載=操作符,轉為呼叫insert
    insert_iterator<Container>& operator=(const typename Container::value_type& value) {
        iter = container->insert(iter, value);
        ++iter;
        return *this;
    }
    
    insert_iterator<Container>& operator*() { return *this; }
    insert_iterator<Container>& operator++() { return *this; }
    insert_iterator<Container>& operator++(int) { return *this; }
};

template <class Container, class Iterator>
inline insert_iterator<Container> inserter(Container& x, Iterator i) {
  typedef typename Container::iterator iter;
  return insert_iterator<Container>(x, iter(i));
}

int main()
{
    std::list<int> lst = {1,2,3};
    auto backItor = std::back_inserter(lst);
    backItor = 0;									                    // 1230
    auto frontItor = std::front_inserter(lst);
    frontItor= 0;									                        // 01230
    auto insertItor = std::inserter(lst, ++lst.begin());  // 091230,在指定迭代器前插入
    insertItor = 9;

    return 0;
}

reverse Iterators的作用是將迭代器移動的操作進行倒轉。

template <class Iterator>
class reverse_iterator
{
protected:
    Iterator current;
public:
    typedef typename iterator_traits<Iterator>::iterator_category
        iterator_category;
    typedef typename iterator_traits<Iterator>::value_type
        value_type;
    typedef typename iterator_traits<Iterator>::difference_type
        difference_type;
    typedef typename iterator_traits<Iterator>::pointer
        pointer;
    typedef typename iterator_traits<Iterator>::reference
        reference;

    typedef Iterator iterator_type;
    typedef reverse_iterator<Iterator> self;

public:
    reverse_iterator() {}
    
    // 關聯迭代器
    explicit reverse_iterator(iterator_type x) : current(x) {}
    reverse_iterator(const self& x) : current(x.current) {}

    iterator_type base() const { return current; }

	// 過載*操作符為後退一步取值
    reference operator*() const {
        Iterator tmp = current;
        return *--tmp;
    }
    pointer operator->() const { return &(operator*()); }

	// 過載++操作符為--
    self& operator++() {
        --current;
        return *this;
    }
    self operator++(int) {
        self tmp = *this;
        --current;
        return tmp;
    }

	// 過載--操作符為++
    self& operator--() {
        ++current;
        return *this;
    }
    self operator--(int) {
        self tmp = *this;
        ++current;
        return tmp;
    }

    self operator+(difference_type n) const {
        return self(current - n);
    }
    self& operator+=(difference_type n) {
        current -= n;
        return *this;
    }
    self operator-(difference_type n) const {
        return self(current + n);
    }
    self& operator-=(difference_type n) {
        current += n;
        return *this;
    }
    
    reference operator[](difference_type n) const { return *(*this + n); }
};

stream Iterators的作用是將迭代器繫結到stream物件上,包括istream和ostream。

template <class T, class Distance = ptrdiff_t>
class istream_iterator {
    friend bool
        operator== __STL_NULL_TMPL_ARGS(const istream_iterator<T, Distance>& x,
            const istream_iterator<T, Distance>& y);
protected:
    istream* stream;
    T value;
    bool end_marker;
    void read() {
        end_marker = (*stream) ? true : false;
        if (end_marker) *stream >> value;               // 將輸入流賦值給value
        end_marker = (*stream) ? true : false;
    }
public:
    typedef input_iterator_tag iterator_category;
    typedef T                  value_type;
    typedef Distance           difference_type;
    typedef const T*           pointer;
    typedef const T&           reference;

    istream_iterator() : stream(&cin), end_marker(false) {}
    istream_iterator(istream& s) : stream(&s) { read(); }
    reference operator*() const { return value; }
    pointer operator->() const { return &(operator*()); }

	// 每當遇到++操作符時讀入
    istream_iterator<T, Distance>& operator++() {
        read();
        return *this;
    }
    istream_iterator<T, Distance> operator++(int) {
        istream_iterator<T, Distance> tmp = *this;
        read();
        return tmp;
    }
};

template <class T>
class ostream_iterator {
protected:
    ostream* stream;
    const char* string;
public:
    typedef output_iterator_tag iterator_category;
    typedef void                value_type;
    typedef void                difference_type;
    typedef void                pointer;
    typedef void                reference;

    ostream_iterator(ostream& s) : stream(&s), string(0) {}
    ostream_iterator(ostream& s, const char* c) : stream(&s), string(c) {}

	// 每當遇到=操作符時,將value輸出到輸出流,同時支援分隔符
    ostream_iterator<T>& operator=(const T& value) {
        *stream << value;
        if (string) *stream << string;
        return *this;
    }
    
	// 禁止部分操作符
    ostream_iterator<T>& operator*() { return *this; }
    ostream_iterator<T>& operator++() { return *this; }
    ostream_iterator<T>& operator++(int) { return *this; }
};

int main()
{
    std::list<int> lst;
    lst.resize(5);

    std::istream_iterator<int> in(std::cin);
    std::istream_iterator<int> eof;                     // 輸入結束符,windows控制檯中可以用Ctrl+Z
    std::copy(in, eof, lst.begin());                      // 配合copy使用時,將輸入流拷貝給lst,用到了istream_iterator的++和*操作符

	std::ostream_iterator<int> out(std::cout, ",");
    std::copy(lst.begin(), lst.end(), out);          // 配合copy使用時,將lst拷貝給輸出流,當copy中使用=操作符時就進行輸出

    return 0;
}

輸入輸出結果:
in  << 1 2 3<Ctrl + Z>
out >> 1,2,3

仿函式配接器

容器配接器包含有底層容器,迭代器配接器中包含有容器、迭代器、輸入輸出流程,類似的仿函式配接器包含了底層仿函式。STL中提供了幾個預設的仿函式配接器,以下會進行介紹。

對返回值進行邏輯否定:not1,not2。

template <class Predicate>
class unary_negate
    : public unary_function<typename Predicate::argument_type, bool> {
protected:
    Predicate pred;
public:
    explicit unary_negate(const Predicate& x) : pred(x) {}

	// 對仿函式的結果進行邏輯否
    bool operator()(const typename Predicate::argument_type& x) const {
        return !pred(x);
    }
};

// not1,對一元仿函式進行邏輯否
template <class Predicate>
inline unary_negate<Predicate> not1(const Predicate& pred) {
    return unary_negate<Predicate>(pred);
}

template <class Predicate>
class binary_negate
    : public binary_function<typename Predicate::first_argument_type,
    typename Predicate::second_argument_type,
    bool> {
protected:
    Predicate pred;
public:
    explicit binary_negate(const Predicate& x) : pred(x) {}
	
	// 對仿函式的結果進行邏輯否
    bool operator()(const typename Predicate::first_argument_type& x,
        const typename Predicate::second_argument_type& y) const {
        return !pred(x, y);
    }
};

// not2,對二元仿函式進行邏輯否
template <class Predicate>
inline binary_negate<Predicate> not2(const Predicate& pred) {
    return binary_negate<Predicate>(pred);
}

int main()
{
	// greater原來結果是0程式設計了1,意義是不大於
    std::cout << std::not2(std::greater<int>())(1, 2) << std::endl;   // 1

    return 0;
}

繫結引數:bind1st,bind2nd。

template <class Operation>
class binder1st
    : public unary_function<typename Operation::second_argument_type,
    typename Operation::result_type> {
protected:
    Operation op;
    typename Operation::first_argument_type value;
public:
    binder1st(const Operation& x,
        const typename Operation::first_argument_type& y)
        : op(x), value(y) {}
    typename Operation::result_type
        operator()(const typename Operation::second_argument_type& x) const {
        return op(value, x);
    }
};

template <class Operation, class T>
inline binder1st<Operation> bind1st(const Operation& op, const T& x) {
    typedef typename Operation::first_argument_type arg1_type;
    return binder1st<Operation>(op, arg1_type(x));
}

template <class Operation>
class binder2nd
    : public unary_function<typename Operation::first_argument_type,
    typename Operation::result_type> {
protected:
    Operation op;
    typename Operation::second_argument_type value;
public:
    binder2nd(const Operation& x,
        const typename Operation::second_argument_type& y)
        : op(x), value(y) {}
    typename Operation::result_type
        operator()(const typename Operation::first_argument_type& x) const {
        return op(x, value);
    }
};

template <class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) {
    typedef typename Operation::second_argument_type arg2_type;
    return binder2nd<Operation>(op, arg2_type(x));
}

int main()
{
	// 將10繫結到equal_to的第一個引數中,返回一個仿函式物件
    auto equal10 = std::bind1st(std::equal_to<int>(), 10);
    std::cout << equal10(1) << std::endl;         // 0
    std::cout << equal10(10) << std::endl;       // 1

	// 配合使用,移除容器中所有小於等於2的元素
	// remove_if接收一個區間,並接收一個一元仿函式物件,會將區間中仿函式返回true的元素都放到為區間尾部
	// 配合erase移除區間尾部的元素
	std::vector<int> vec = { 1,2,3,4,5 };
    vec.erase(
        std::remove_if(vec.begin(), vec.end(), std::bind2nd(std::less_equal<int>(), 2)),   // 將小於等於仿函式繫結為一元仿函式物件
        vec.end()
    );
    return 0;
}

用於函式合成:compose1,compose2。這兩個仿函式配接器是SGI STL特有的,不屬於STL標準。

template <class Operation1, class Operation2>
class unary_compose : public unary_function<typename Operation2::argument_type,
    typename Operation1::result_type> {
protected:
    Operation1 op1;
    Operation2 op2;
public:
    unary_compose(const Operation1& x, const Operation2& y) : op1(x), op2(y) {}
    typename Operation1::result_type
        operator()(const typename Operation2::argument_type& x) const {
        return op1(op2(x));
    }
};

// 將仿函式2的結果作為仿函式1的引數
template <class Operation1, class Operation2>
inline unary_compose<Operation1, Operation2> compose1(const Operation1& op1, const Operation2& op2) {
    return unary_compose<Operation1, Operation2>(op1, op2);
}

template <class Operation1, class Operation2, class Operation3>
class binary_compose
    : public unary_function<typename Operation2::argument_type,
    typename Operation1::result_type> {
protected:
    Operation1 op1;
    Operation2 op2;
    Operation3 op3;
public:
    binary_compose(const Operation1& x, const Operation2& y,
        const Operation3& z) : op1(x), op2(y), op3(z) { }
    typename Operation1::result_type
        operator()(const typename Operation2::argument_type& x) const {
        return op1(op2(x), op3(x));
    }
};

// 將仿函式2、3的結果作為仿函式1的引數
template <class Operation1, class Operation2, class Operation3>
inline binary_compose<Operation1, Operation2, Operation3>
compose2(const Operation1& op1, const Operation2& op2, const Operation3& op3) {
    return binary_compose<Operation1, Operation2, Operation3>(op1, op2, op3);
}

用於函式指標:ptr_fun。將函式指標轉換成仿函式物件,便於和STL中的演算法和仿函式進行配合使用,因為單純的函式指標是無法進行配接的。

template <class Arg, class Result>
class pointer_to_unary_function : public unary_function<Arg, Result> {
protected:
    Result(*ptr)(Arg);
public:
    pointer_to_unary_function() {}
    explicit pointer_to_unary_function(Result(*x)(Arg)) : ptr(x) {}
    Result operator()(Arg x) const { return ptr(x); }
};

// 將一元函式指標轉換成一元仿函式物件
template <class Arg, class Result>
inline pointer_to_unary_function<Arg, Result> ptr_fun(Result(*x)(Arg)) {
    return pointer_to_unary_function<Arg, Result>(x);
}

template <class Arg1, class Arg2, class Result>
class pointer_to_binary_function : public binary_function<Arg1, Arg2, Result> {
protected:
    Result(*ptr)(Arg1, Arg2);
public:
    pointer_to_binary_function() {}
    explicit pointer_to_binary_function(Result(*x)(Arg1, Arg2)) : ptr(x) {}
    Result operator()(Arg1 x, Arg2 y) const { return ptr(x, y); }
};

// 將二元函式指標轉換成二元仿函式物件
template <class Arg1, class Arg2, class Result>
inline pointer_to_binary_function<Arg1, Arg2, Result>
ptr_fun(Result(*x)(Arg1, Arg2)) {
    return pointer_to_binary_function<Arg1, Arg2, Result>(x);
}

// 使用舉例
int add(int a, int b)
{
    return a + b;
}

int main()
{
    auto addFunc = std::ptr_fun(&add);
    std::cout << addFunc(1, 2);

    return 0;
}

用於成員函式指標:mem_fun、mem_fun_ref。作用和ptr_fun類似,不過是用於成員函式。

template <class T>
class mem_fun_t<void, T> : public unary_function<T*, void> {
public:
    explicit mem_fun_t(void (T::*pf)()) : f(pf) {}
    void operator()(T* p) const { (p->*f)(); }             // 使用成員函式指標進行函式呼叫
private:
    void (T::*f)();
};

template <class S, class T>
inline mem_fun_t<S, T> mem_fun(S(T::*f)()) {
    return mem_fun_t<S, T>(f);
}

template <class S, class T>
class mem_fun_ref_t : public unary_function<T, S> {
public:
    explicit mem_fun_ref_t(S(T::*pf)()) : f(pf) {}
    S operator()(T& r) const { return (r.*f)(); }        // 使用成員函式對引用進行函式呼叫
private:
    S(T::*f)();
};

template <class S, class T>
inline const_mem_fun_ref_t<S, T> mem_fun_ref(S(T::*f)() const) {
    return const_mem_fun_ref_t<S, T>(f);
}

int main()
{
    std::vector<Example*> vec = {
        &Example(1),
        &Example(2),
        &Example(3),
        &Example(4),
        &Example(5)};
    std::for_each(vec.begin(), vec.end(), std::mem_fun(&Example::printOut));   // 1,2,3,4,5

    return 0;
}