日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STL源码剖析(四)

發(fā)布時間:2025/3/15 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STL源码剖析(四) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

functors

仿函數(shù)(functor),就是使一個類的使用看上去像一個函數(shù)。其實現(xiàn)就是類中實現(xiàn)一個operator(),這個類就有了類似函數(shù)的行為,就是一個仿函數(shù)類了。

在STL中,將仿函數(shù)主要分為了三大類:算術類(Arithmetic)、邏輯運算類(Logical)和相對關系類(Relational)。

算術類(Arithmetic)舉例

template <class T> struct plus : public binary_function<T, T, T> {T operator()(const T& x, const T& y) const{ return x + y; } };template <class T> struct minus : public binary_function<T, T, T> {T operator()(const T& x, const T& y) const{ return x - y; } };...

邏輯運算類(Logical)舉例

template <class T> struct logical_and : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const{ return x && y; } };...

相對關系類(Relational)

template <class T> struct equal_to : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const{ return x == y; } };template <class T> struct less : public binary_function<T, T, bool> {bool operator()(const T& x, const T& y) const{ return x < y; } };...

通過上面的代碼可以發(fā)現(xiàn),functors都繼承了一個基類。STL規(guī)定每個 Adaptable Function 都應該挑選合適的父類繼承,因為 Adaptable Function 將會提問一些問題。

template <class Arg, class Result> struct unary_function {typedef Arg argument_type;typedef Result result_type; };template <class Arg1, class Arg2, class Result> struct binary_function {typedef Arg1 first_argument_type;typedef Arg2 second_argument_type;typedef Result result_type; };

比如上面的less通過繼承binary_function擁有了3個typedef,這些typedef可能會在一些適配器中被詢問到,詳見后面適配器中的源碼。

Adapters

Adapters 相當于一種修飾的作用,在容器、迭代器和仿函數(shù)的基礎上,對其進行一種改造。將改造完成后的容器、迭代器或仿函數(shù)交給用戶使用,但其核心還是通過內(nèi)部的容器、迭代器和仿函數(shù)進行工作。所以就存在: Container Adapters, Iterator Adapters 和 Functor Adapters三類。

容器適配器:stack, queue

stack

template <class T, class Sequence=deque<T>> class stack{ ... public:typedef typename Sequence::value_type value_type;typedef typename Sequence::size_type size_type;typedef typename Sequence::reference reference;typedef typename Sequence::const_reference const_reference; proctected:Sequence c;// 底層容器 public:bool empty() const { return c.empty(); }size_type size() const { return c.size(); }reference top() { return c.back(); }const_reference top const { return c.back(); }void push(const value_type& x) { c.push_back(x); }void pop { c.pop_back(); } };

queue

template <class T, class Sequence=deque<T>> class queue{ ... public:typedef typename Sequence::value_type value_type;typedef typename Sequence::size_type size_type;typedef typename Sequence::reference reference;typedef typename Sequence::const_reference const_reference; proctected:Sequence c;// 底層容器 public:bool empty() const { return c.empty(); }size_type size() const { return c.size(); }reference front() { return c.front(); }const_reference front() const { return c.front(); }reference back() { return c.back(); }const_reference back() const { return c.bakc(); }void push(const value_tyoe& x) { c.push_back(x); }void pop { c.pop_back(); } };

函數(shù)適配器:binder2nd, not1

對于這樣一行語句:

cout << count_if(vi.begin(), vi.end(), not1(bind2nd(less<int>(), 40));

首先需要注意的是less<int>()這并不是函數(shù)的調(diào)用,而是生成一個less<int>的對象!

count_if

template <class InputIterator, class Predicate> typename iterator_traits<InputIterator>::difference_type count_if(InputIterator first, InputIterator last, Predicate pred){typename iterator_traits<InputIterator>::difference_type n = 0;for(; first != last; ++first)if(pred(*first))++n;return n; }

bind2nd

template <class Operation, class T> inline binder2nd<Operation> bind2nd(const Operation& op,const T& x) {typedef typename Operator::second_argument_type arg2_type;return binder2nd<Operation>(op, arg2_type(x));//返回一個binder2nd<Operation>對象! }

binder2nd

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);//這里才是函數(shù)的調(diào)用} };

在這些代碼中可以看到適配器在詢問仿函數(shù)一些問題,這些問題就是仿函數(shù)繼承的基類中的typedef。所有能回答出這些問題的仿函數(shù)都稱為 Adaptable Function

not1

template <class Predicate> inline unary_negate<Predicate> not1(consat Predicate& pred) {return unary_negate<Predicate>(pred); }template <class Predicate> class unary_negate : public unart_function<typename Predicate::argument_type, bool> { protected:Predicate pred; public:eplicit unary_negate(const Predicate& x) : pred(x) {}bool operator()(const typename Predicate::argument_type& x) const{return !pred(x);} };

新型適配器,bind

bind 使用例子(摘自cplusplus網(wǎng)站)

#include <iostream> // std::cout #include <functional> // std::bind// a function: (also works with function object: std::divides<double> my_divide;) double my_divide (double x, double y) {return x/y;}struct MyPair {double a,b;double multiply() {return a*b;} };int main () {using namespace std::placeholders; // adds visibility of _1, _2, _3,...// binding functions:auto fn_five = std::bind (my_divide,10,2); // returns 10/2std::cout << fn_five() << '\n'; // 5auto fn_half = std::bind (my_divide,_1,2); // returns x/2std::cout << fn_half(10) << '\n'; // 5auto fn_invert = std::bind (my_divide,_2,_1); // returns y/xstd::cout << fn_invert(10,2) << '\n'; // 0.2auto fn_rounding = std::bind<int> (my_divide,_1,_2); // returns int(x/y)std::cout << fn_rounding(10,3) << '\n'; // 3MyPair ten_two {10,2};// binding members: member function 其實有個 argument: thisauto bound_member_fn = std::bind (&MyPair::multiply,_1); // returns x.multiply()std::cout << bound_member_fn(ten_two) << '\n'; // 20auto bound_member_data = std::bind (&MyPair::a,ten_two); // returns ten_two.astd::cout << bound_member_data() << '\n'; // 10return 0; }

std::bind 可以綁定:

  • functions
  • function objects
  • member functions, _1 必須是某個object地址
  • data members, _ 必須是某個object地址
  • 所以可以現(xiàn)在可以用bind替換bind2nd,改寫如下:

    vector<int> v {15,37,94,50,73,58,28,98}; int n = count_if(v.cbegin(), v.cend(), not1(bind2nd(less<int>, 50))); cout << "n=" << n << endl;//5vector<int> v {15,37,94,50,73,58,28,98}; int n = count_if(v.cbegin(), v.cend(), not1(bind(less<int>, _1, 50))); cout << "n=" << n << endl;//5

    迭代器適配器 reverse_iterator, inserter

    reverse_iterator:用來實現(xiàn)去反向指針rbegin(), rend()的實現(xiàn)。

    reverse_iterator rbegin() { return reverse_iterator(end()); }reverse_iterator rend() { returun reverse_iterator(begin()); }template <class Iterator> class reverse_iterator { protected:Iterator current;//對應的正向迭代器 public://逆向迭代器的5中 associated types 都和對應的正向迭代器相同typedef typename iterator_traits<Iterator>::iterator_category iterator_category;typedef typename iterator_traits<Iterator>::value_type value_type;...typedef Iterator iterator_type; // 表示正向迭代器typedef reverse_iterator<Iterator> self;// 表示反向迭代器 public: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--() { ++current; return *this; }slef operator+(difference_type n) const { return self(current - n); }slef operator-(difference_type n) const { return self(current + n); } };

    inserter: 將iteartor中的復制操作改為插入操作,并且將iteartor右移一個位子。可以讓用戶執(zhí)行表面上assign而實際上insert的行為。

    template <class Container> class insert_iterator { protected:Container* container;typename Container::iterator iter; pbulic:typedef output_iterator_tag iterator_category;insert_iterator(Container& x, typename Container::iterator i) : container(&x), iter(i) {}//對賦值操作符重載,以實現(xiàn)插入insert_iterator<Contain>& operator=(const typename Container::value_type& value){iter = container->insert(iter, value);++iter;return *thisl} };//輔助函數(shù),幫助用戶使用insert_iterator 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)); }

    特殊適配器 ostream_iterator, istream_iterator

    ostream_iterator

    先來看一個例子

    #include <iostream> //std::cout #include <iterator> //std::ostream_iterator #include <vector> //std::vector #include <algorithm> //std::copyint main() {std::vector<int> myvector;for (int i = 1; i < 10; ++i) myvector.push_back(i * 10);std::ostream_iterator<int> out_it(std::cout, ",");std::copy(myvector.begin(), muvector.end(), out_it);return 0; }

    輸出結果:

    10,20,30,40,50,60,70,80,90,

    首先來看看copy這個函數(shù)做了什么

    template<class InputIterator first, InputIterator last,OutputIterator result> copy(InputIterator first,InputIterator last, OutputIterator result) {while(first != last){*result = *first;++result;++first;} }

    再對比著ostream_iterator的源碼,就能分析出輸出的原因:

    template<class T,class chatT=char,class traits=char_traits<charT>> class ostream_iterator:public iterator<output_iterator_tag,void,void,void,void> {basic_ostream<charT,traits>* out_stream;const charT* delim; public:typedef charT char_type;typedef traits traits_type;typedef basic_ostream<charT,traits> ostream_type;ostream_iterator(ostream_type& s):out_stream(&s),delim(0){}ostream_iterator(onstream_type&s, const charT* delimiter):out_stream(&s),delim(delimiter){}ostream_iterator(const ostream_iterator<T,charT,traits>& x):ostream_iterator(x.out_stream),delim(x.delim){}~ostream_iterator(){}ostream_iterator<T,chatT,traits>& operator=(const T& value){//關鍵點!!*out_stream << value;if(delim!=0) *out_stream << delim;return *this;}ostream_iterator<T,charT,traits>& operator*(){return *this;}ostream_iterator<T,charT,traits>& operator++(){return *this;}ostream_iterator<T,charT,traits>& operator++(int){return *this;} };

    關鍵就在于重載了=號運算符。

    istream_iterator

    還是先看一個例子

    #include <iostream> #include <iterator>int main() {double value1, value2;std::cout << "Please, insert two values:";std::istream_iterator<double> eos;std::istream_iterator<double> iit(std::cin);//當創(chuàng)建對象時,就已經(jīng)在要求輸入了if (iit != eos)value1 = *iit;++iit;if (iit != eos)value2 = *iit;std::cout << value1 << "*" << value2 << "=" << (value1*value2) << "\n";return 0; }

    這個例子就是一個簡單的乘法,其中std::istream_iterator<double> iit(std::cin);相當于cin >> value;。具體的原理還是看源碼吧。

    template <class T, class charT = char, class traits = char_traits<charT>>, class Distance = ptrdiff_t > class istream_iterator : public iterator<input_iterator_tag, T, Distance, const T*, const T&> {basic_istream<charT, traits>* instream;T value; public:typedef charT char_type;typedef traits traits_type;typedef basic_istream<charT, traits> istream_type;istream_iterator() :instream(0) {}istream_iterator(istream_type& s) :in_stream(&s) { ++*this; }istream_iterator(const istream_iterator) < T, charT, traits, Distance > & x):in_stream(x.in_stream), value(x.value){}~istream_itetator() {}const T& operator*() const { return value; }const T* operator->() const { return value; }istream_iterator<T, charT, traits, Distance>& operator++() {if (in_stream && !(*in_stream >> value))in_stream = 0;return *this;}istream_iterator<T,charT,traits,Distance>operator++(int) {istream_iterator<T, charT, traits, Distance> tmp = *this;++*this;return tmp;} };

    對照源碼可以發(fā)現(xiàn),std::istream_iterator<double> iit(std::cin);這里調(diào)用了istream_iterator的++符號,此時就已經(jīng)開始輸入了。

    轉載于:https://www.cnblogs.com/joker-wz/p/10299617.html

    總結

    以上是生活随笔為你收集整理的STL源码剖析(四)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。