STL_Adapter

咖啡豆

STL_Adapter

1. 配接器之概观与分类

STL所提供的各种配接器中,改变仿函数(functors)接口者,我们称之为 function adapter,改变容器(containers)接口者,我们称之为 container adapter,改变迭代器(iterator)接口者,我们称之为 iterator adapter

《STL源码剖析》 – P425


1.1 container adapters

STL提供的两个容器 queuestack,其实都不过是一种配接器,他们修饰 deque 的接口而成就出另外一种容器风貌。

《STL源码剖析》 – P425

1.2 iterator adapters

STL 提供了许多应用于迭代器身上的配接器

  • insert iterators
    • back_insert_iterator
    • front_insert_iterator
    • insert_iterator
  • reverse iterator
  • iostream iterator
    • istream_iterator
    • ostream_iterator

《STL源码剖析》 – P425 - P428

1.3 function adapters

functor adapter 是所有配接器中数量最庞大的一个族群,其配接灵活度也是前两者不能及的,可以配接、配接、再配接,这些配接操作包括绑定(bind)、否定(negate),组合(compose),以及对一函数或成员函数的修饰(使其成为一个仿函数)

《STL源码剖析》 – P428 - P433


2. container adapters

2.1 stack

stack 的底层由 deque 构成,从以下接口可以清楚的看出 stackdeque 的关系:

1
2
3
4
5
6
template <class T, class Sequence = deque<T>>
class stack {
protected:
Sequence c; // 底层容器
....
};

《STL源码剖析》 – P434


2.2 queue

queue 的底层由 deque 构成,从以下接口可以清楚的看出 stackdeque 的关系:

1
2
3
4
5
6
template <class T, class Sequence = deque<T>>
class queue {
protected:
Sequence c; // 底层容器
....
};

《STL源码剖析》 – P434


3. iterator adapters

3.1 insert iterators

下面三种 insert iterators 内部都维护了一个容器(必须由用户指定);容器当然需要拥有自己的迭代器。于是,当客户端对 insert iterators 做赋值(assign)操作时,就在 insert iterators 中被转为对该容器的迭代器做插入(insert)操作,也就是说,insert iteratorsoperator= 操作符中调用底层容器的 push_back()push_front(), insert() 操作函数。至于其他迭代器通常行为如 operator++operator++(int)operator* 都被关闭功能,更没有 operator--, operator--(int), operator-> 等功能,所以被定义为 output_iterator_tag

《STL源码剖析》 – P435


3.1.1 back_insert_iterator

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
template <class Container>
class back_insert_iterator {
protected:
Container *container; // ~ 底层容器
public:
using iterator_category = output_iterator_tag; // 注意迭代器类型
using value_tyep = void;
using difference_type = void;
using pointer = void;
using reference = void;

public:
explicit back_insert_iterator(Container &value) : container(value) {}
back_insert_iterator &operator=(const typename Container::value_type &value) {
container->push_back(value); // ~ 本质上是调用了push_back
return *this;
}

// ~ 以下三个接口对 back_insert_iterator 无用, 关闭功能, 直接返回
back_insert_iterator operator*() { return *this; }
back_insert_iterator operator++() { return *this; }
back_insert_iterator operator++(int) { return *this; }
};

// ~ 以下是一个辅助函数,便于快速使用 back_insert_iterator
template <class Container>
inline back_insert_iterator<Container> back_inserter(Container &x) {
return back_insert_iterator<Container>(x);
}

《STL源码剖析》 – P435 - P436


3.1.2 front_insert_iterator

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
template <class Container>
class front_insert_iterator {
protected:
Container *container; // ! 底层容器
public:
using iterator_category = output_iterator_tag;
using value_tyep = void;
using difference_type = void;
using pointer = void;
using reference = void;

public:
explicit front_insert_iterator(Container &value) : container(value) {}
front_insert_iterator &operator=(const typename Container::value_type &value) {
container->push_front(value); // ~ 本质上是调用了push_front
return *this;
}

// ! 以下三个接口对 front_insert_iterator无用, 关闭功能
front_insert_iterator operator*() { return *this; }
front_insert_iterator operator++() { return *this; }
front_insert_iterator operator++(int) { return *this; }
};

// ! 以下是一个辅助函数,便于快速使用 front_insert_iterator
template <class Container>
inline front_insert_iterator<Container> front_inserter(Container &x) {
return front_insert_iterator<Container>(x);
}

需要注意的是,底层的容器要支持迭代器,并且支持 push_front() 的操作。

《STL源码剖析》 – P436


3.1.3 insert_iterator

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
template <class Container>
class insert_iterator {
protected:
Container *container; // @ 底层容器
typename Container::iterator iter;

public:
using iterator_category = output_iterator_tag;
using value_tyep = void;
using difference_type = void;
using pointer = void;
using reference = void;

public:
insert_iterator(Container &value, typename Container::iterator i) : container(value), iter(i) {}
insert_iterator &operator=(const typename Container::value_type &value) {
container->insert(iter, value); // @ 调用insert
++iter; // @ 保证insert_iterator永远与目标贴合(感觉形式作用大于实际作用)
return *this;
}

// @ 以下三个接口对insert_iterator 无用,关闭功能
insert_iterator operator*() { return *this; }
insert_iterator operator++() { return *this; }
insert_iterator operator++(int) { return *this; }
};
// @ 以下是一个辅助函数,便于快速使用 insert_iterator
template <class Container, class Iterator>
inline insert_iterator<Container> inserter(Container &x, Iterator i) {
return insert_iterator<Container>(x, i);
}

《STL源码剖析》 – P437


3.2 reverse iterator

所谓的 reverse iterator,就是将迭代器的移动行为倒转。如果 STL 算法接受的不是一般正常的迭代器,而是这种逆向的迭代器,它就会以从尾到头的方向来处理序列中的元素。如 rbegin()rend()

注意:单项序列容器如 slist 不可以使用 reserve iterator,有些容器如 stackqueuepriority_queue 并不提供 begin()end(),当然也没有 rbegin()rend()

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
// # reverse_iterator
template <class Iterator>
class __reverse_iterator {
protected:
Iterator current; // # 与之对应的正向迭代器
public:
using iterator_category = iterator_category_t<Iterator>;
using value_type = value_type_t<Iterator>;
using difference_type = difference_type_t<Iterator>;
using pointer = pointer_t<Iterator>;
using reference = reference_t<Iterator>;

using iterator_type = Iterator; // # 正向迭代器
using self = __reverse_iterator; // # 反向迭代器

public:
__reverse_iterator() {}
explicit __reverse_iterator(iterator_type value) : current(value) {} // # 构造函数
__reverse_iterator(const self &value) : current(value.current) {} // # 拷贝构造函数
// # 返回正向迭代器,即反向迭代器往 rbegin() 进一步的那个位置, 与下面对应 ↓
iterator_type base() const { return current; }
reference operator*() const {
Iterator temp = current;
return *--temp; // # 对逆向迭代器的取值等价于对应的正向迭代器后退一个单位取值
// # * -- 优先级相同,从右至左, *--temp = *(--temp)
}

pointer operator->() const { return &(operator*()); }
// # 相关迭代器的操作都是反向操作
self &operator++() { // # 前置
--current;
return *this;
}
self operator++(int) { // # 后置
self temp = *this;
--current;
return temp;
}
self &operator--() { // # 前置
++current;
return *this;
}
self operator--(int) { // # 后置
self temp = *this;
++current;
return temp;
}
self operator+(difference_type n) const { return self(current - n); }
self &operator+=(difference_type n) const {
current -= n;
return *this;
}
self operator-(difference_type n) const { return self(current + n); }
self &operator-=(difference_type n) const {
current += n;
return *this;
}
// # 注意此时operator[]前进 n 格,其中调用了重载版本的 operator+,与正向迭代器相反
reference operator[](difference_type n) const { return *(*this + n); }

bool operator==(const self &rhs) const { return current == rhs.current; }
bool operator!=(const self &rhs) const { return !((*this) == rhs); }
};

正向迭代器与对应的逆向迭代器取出不同元素,这个并不是一个潜伏的错误,而是一个刻意为之的特征,主要配合迭代器区间的“前闭后开”习惯,如下图所示。

图 1 逆向迭代器前闭后开逻辑

小例子:

1
2
3
4
5
6
7
deque<int> id{1, 0, 1, 2, 3, 4, 0, 1, 2, 5, 3}
deque<int>::reverse_iterator rite2(id.end());
cout << *(rite2); // 3
cout << *(++++++rite2); // 1 (前进 3 个位置后取值)
cout << *(--rite2); // 2 (后退 1 个位置后取值)
cout << *(rite2.base()); // 5 (恢复正向迭代器后,取值)
cout << rite2[3]; // 4 (前进 3 个位置后取值)

每个步骤的移动见下图所示:

图 2 逆向迭代器小例子

《STL源码剖析》 – P437 - P442

上述的小例子来自于 P441 ↑


3. 3 stream iterator

所谓 stream iterator,可以将迭代器绑定到一个 stream 对象上,绑定到 istream 对象者,称之为 istream_iterator,拥有输入能力;绑定到 ostream 对象者,称之为 ostream_iterator,拥有输出能力。

3.3.1 istream_iterator

所谓绑定一个 istream object,其实就是在 istream iterator 内部维护一个 istream member,客户端对于这个迭代器所作的 operator++ 操作,会被导引调用迭代器内部所含的那个 istream member 的输入操作(operator>>),这个迭代器的类型是 input_iterator_tag,不具备 operator--

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
// $ stream: input_stream

template <class T, class Distance = ptrdiff_t>
class istream_iterator {
protected:
std::istream *stream; // istream 对象
T value;
bool end_marker;
void read() {
end_marker = (*stream) ? true : false;
if (end_marker) *stream >> value; // $ 关键
end_marker = (*stream) ? true : false;
// $ 完成输入后,stream 状态可能发生了改变,再次判定
// $ 当读到 eof 或读到性别不符的资料,stream 即出与 false 状态
}

public:
using iterator_category = input_iterator_tag; // 类型
using value_tyep = T;
using difference_type = Distance;
using pointer = const T *; // $ 由于为input_iterator,采用const较为保险
using reference = const T &;

istream_iterator() : stream(&std::cin), end_marker(false) {}
istream_iterator(std::istream &s) : stream(&s) { read(); }

reference operator*() const { return value; }
pointer operator->() const { return &(operator*()); }

istream_iterator &operator++() { // $ 迭代器前进一个位置,就代表要读取一笔资料
read();
return *this;
}
istream_iterator operator++(int) { // $ 后置
istream_iterator temp = *this;
read();
return temp;
}
};

使用方法:

1
2
3
4
istream_iterator<int> eos;  		// (A) 造成 end_marker 为 false;
istream_iterator<int> initer(cin); // (B) 引发 read(), 程序至此会等待输入
cout << "please input ..." << endl; // (C)
// $ 注意 C 会等待 B 结束后才运行,所以永远在必要的时候,才定义一个 istream_iterator

通过以上代码可以知道,只要客户端定义一个 istream iterator 并绑定到某个 istream 对象上,程序便立刻停在 istream_iterator<T>::read() 函数,等待输入,这个并不是我们所预期的行为。因此,请在绝对必要的时刻才定义你所需要的 istream iterator

《STL源码剖析》 – P442 - P445


3.3.2 ostream_iterator

所谓绑定一个 ostream object,其实就是在 ostream iterator 内部维护一个 ostream member,客户端对于这个迭代器所作的 operator= 操作,会被导引调用迭代器内部所含的那个 ostream member 的输入操作(operator<<),这个迭代器的类型是 output_iterator_tag

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
template <class T>
class ostream_iterator {
protected:
std::ostream *stream; // ~ 对象
const char *interval; // ~ 输出间隔符, 每次输出后的间隔符号

public:
using iterator_category = output_iterator_tag; // ~ 类型
using value_tyep = void;
using difference_type = void;
using pointer = void;
using reference = void;
// 构造函数
ostream_iterator() : stream(&std::cout), interval(nullptr) {}
ostream_iterator(std::ostream &s, const char *c)
: stream(&s), interval(c) {}
// ~ 对迭代器做赋值操作,就代表要输出一笔资料
ostream_iterator &operator=(const T &value) {
*stream << value; // ~ 关键,输出数值
if (interval) *stream << interval; // ~ 最后输出间隔符
return *this;
}
// ~ 不使用,直接返回原迭代器即可
ostream_iterator &operator*() { return *this; }
ostream_iterator &operator++() { return *this; }
ostream_iterator operator++(int) { return *this; }
};

使用方法:

1
ostream_iterator<int> outiter(cout, ' ');  // ~ 输出至 cout, 每次间隔一个空格

《STL源码剖析》 – P445 - P447


3.3.3 stream_iterator 与 copy() 合作

以下是 stream iteratorcopy() 合作的小例子,由以下两个例子结合

《STL源码剖析》 – P444 istream_iteratorcopy() 合作的例子

《STL源码剖析》 – P447 ostream_iteratorcopy() 合作的例子

实现的功能:手动实时地向 vector 中输入元素,并最后每个元素以一个空格为间隔输出。

书中两个例子如下:

图 3 例子一
图 4 例子二

两者相结合测试用例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <vector>
#include <iterator>
#include <functional>
#include <algorithm>
using namespace std;

int main() {
vector<int> vec;
cout << "int(s) please: " << endl;
istream_iterator<int> iite(cin), eos;
copy(iite, eos, inserter(vec, vec.begin()));
cout << "vec : ";
ostream_iterator<int> oite(cout, " ");
copy(vec.begin(), vec.end(), oite);
return 0;
}

实时输入:

图 5(1) 实时输入

输出结果1:(只要输入不是 int 就会退出)

图 5(2) 以空格间隔输入,char 结尾

输出结果2:

图 5(3) 以回车间隔输入,long 结尾

回车或者空格都可以作为判断截取数据,输出结果1以 end 退出,输出结果2以1212123221222一个超限的大数退出。


4. function adapter

4.1 not1, not2

4.1.1 一元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// $ 对仿函数返回值进行否定配接器
// $ 传入仿函数对象即可,和以前一样使用,仅仅包装了一下子而已。
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); // $ 关键:返回Predicatel临时对象
}
};
// $ 辅助函数,识别传入对象,通过函数模板的参数推导型别,
// $ 并通过函数配接器的构造函数来构造对象并通过operator()返回对象
// $ 辅助函数,用 not1(pred) 来代替 unary_negate<Predicate>(pre)
// $ 传入对象,并返回临时对象
template <class Predicate>
inline unary_negate<Predicate> not1(const Predicate &pred) {
return unary_negate<Predicate>(pred); // $ 返回临时对象
}

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//not1 example
#include <iostream> // std::cout
#include <functional> // std::not1
#include <algorithm> // std::count_if

using namespace std;

struct IsOdd { // 自定义判断奇偶类
bool operator() (const int& x) const {return x % 2 == 1;}
typedef int argument_type; // 定义一个型别
};

int main () {
int values[] = {1,2,3,4,5};
// 找出不是奇数的个数
int cx = count_if(values, values + 5, not1(IsOdd()));
// IsOdd()产生临时对象 temp1, not1 使用 temp1 调用仿函数,并返回临时对象 temp2。
cout << "There are " << cx << " elements with even values.\n" << endl;
return 0;
}
// output: There are 2 elements with even values.

《STL源码剖析》 – P451

STL之仿函数实现详解 <-- 例子来源


4.1.2 二元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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); // $ 关键
}
};
// $ 辅助函数
template <class _Predicate>
inline binary_negate<_Predicate> not2(const _Predicate &pred) {
return binary_negate<_Predicate>(pred); // 返回临时对象
}

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// not2 example
#include <iostream> // std::cout
#include <functional> // std::not2, std::equal_to
#include <algorithm> // std::mismatch
#include <utility> // std::pair

int main () {
int foo[] = {10,20,30,40,50};
int bar[] = {0,15,30,45,60};

std::pair<int*,int*> firstmatch, firstmismatch;
//返回第一个不匹配数值
firstmismatch = std::mismatch (foo, foo + 5, bar, std::equal_to<int>());
//返回第一个匹配的数值
firstmatch = std::mismatch (foo, foo + 5, bar, std::not2(std::equal_to<int>()));

std::cout << "First mismatch in bar is " << *firstmismatch.second << '\n';
std::cout << "First match in bar is " << *firstmatch.second << '\n';
return 0;
}
// output : First mismatch in bar is 0
// : First match in bar is 30

《STL源码剖析》 – P451

STL之仿函数实现详解 <-- 例子来源


4.2 bind1st, bind2nd

4.2.1 bind1st

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
template <class Operation>  
// ~ Operation 为仿函数类, 原来二元的操作,通过绑定其中一个参数,变成了一元操作
class binder1st // ~ ↓ 绑定了 first, bunary_function 的 参数变成了 secondresult
: public unary_function<typename Operation::second_argument_type, typename Operation::result_type> {
protected:
Operation op; // ~ 仿函数对象
typename Operation::first_argument_type value;
// ~ 用 first_argument_type 声明 value

public: // ~ 构造函数 : 仿函数对象传入 op, 绑定值传入 value
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); // ~ 调用表达式,将 value 作为第一参数
}
};
// ~ 辅助函数
template <class Operation, class T>
inline binder1st<Operation> bind1st(const Operation &op, const T &x) {
using Arg1_type = typename Operation::first_argument_type;
return binder1st<Operation>(op, static_cast<Arg1_type>(x)); // ~ 返回临时对象
}

《STL源码剖析》 – P452


4.2.2 bind2nd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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) {
using Arg2_type = typename Operation::second_argument_type;
return binder2nd<Operation>(op, Arg2_type(x));
}

《STL源码剖析》 – P452 - P453


4.2.3 使用

下面的例子,使用了 binder1st,与 binder2nd,并分别通过:① binder1st 直接生成函数对象和② 辅助函数 bind2nd 生成函数对象,实现了不同的功能,前者找出负数的个数,后者找出正数的个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// binder1st example
// binder2nd example
#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;

int main () {
int numbers[] = {10,-20,-30,40,-50};
int cx_1;
int cx_2;
// ~ 将less<int>重新包装产生新的对象 binder1st
binder1st<less<int>> IsNegative (less<int>(), 0);
cx_1 = count_if(numbers, numbers + 5 , IsNegative); // ~ 使用函数对象
cx_2 = count_if(numbers, numbers + 5, bind2nd(less<int>(), 0)); // 使用辅助函数生成函数对象
cout << "There are " << cx_1 << " negative elements.\n";
cout << "There are " << cx_2 << " positive elements.\n";
return 0;
}
// ~ output: There are 2 negative elements.
// ~ There are 3 positive elements.

例子改写于 --> STL之仿函数实现详解


4.3 compose and compose2

4.3.1 compose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ! 将两个仿函数合并成一个仿函数的适配器
// ! 一元仿函数的合成操作 h(x) = f(g(x))
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));
}
};
// ! 辅助函数
template <class Operation1, class Operation2>
inline unary_compose<Operation1, Operation2> compose1(const Operation1 &op1, const Operation2 &op2) {
return unary_compose<Operation1, Operation2>(op1, op2); // ! 返回临时对象

《STL源码剖析》 – P453


4.3.2 compose2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ! 二元仿函数合成操作   h(x) = f(g1(x), g2(x))
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));
}
};
// ! 辅助函数
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);
}

《STL源码剖析》 – P453 - P454


4.4 用于函数指针:ptr_fun

4.4.1 将函数指针包装成仿函数的配接器

具体的代码见:

《STL源码剖析》 – P455

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// # ptr_fun example
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <numeric>
using namespace std;

int main () {
char* foo[] = {"10","20","30","40","50"};
int bar[5];
int sum;
// # 将函数指针转换成仿函数对象,这里输入函数指针效果一样
transform (foo, foo + 5, bar, ptr_fun(atoi) );
transform (foo, foo + 5, bar, atoi);
sum = accumulate (bar, bar + 5, 0);
cout << "sum = " << sum << endl;
return 0;
}
// # output: sum = 150

STL之仿函数实现详解 <-- 例子来源


4.4.2 将成员函数指针包装成仿函数的配接器

具体的代码及相关内容见:

《STL源码剖析》 – P456 - P460

使用:

mem_fun 写法:

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
// @ mem_fun example
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int main() {
// vector 里面存的是指向string对象的指针
vector<string*> num;
num.push_back ( new string ("one") );
num.push_back ( new string ("two") );
num.push_back ( new string ("three") );
num.push_back ( new string ("four") );
num.push_back ( new string ("five") );

vector<int> len(num.size());
// 从内部可以看出:S operator()(T *p) const { return (p->*f)(); }
// men_fun 在指针上通过指向成员的指针访问成员
transform(num.begin(), num.end(), len.begin(), mem_fun(&string::size));

for (int i=0; i<5; i++) {
cout << *numb[i] << " has " << len[i] << " letters.\n";
}
// 析构,不要忘了 new 的要记得释放掉
for (auto it = num.begin(); it != num.end(); ++it)
delete *it;

return 0;
}
// @ output: one has 3 letters.
// @ two has 3 letters.
// @ three has 5 letters.
// @ four has 4 letters.
// @ five has 4 letters.

mem_fun_ref 写法:

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
// @ mem_fun example
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <string>

using namespace std;


int main () {
// vector 里面存的是string对象
vector<string> num{"one", "two", "three", "four", "five"};
vector<int> len(num.size());
// 从内部可以看出:S operator()(T &r) const { return (r.*f)(); }
// mem_fun_ref 在对象上通过指向成员的指针访问成员的操作
transform(num.begin(), num.end(), len.begin(), mem_fun_ref(&string::size));
for (int i=0; i<5; i++) {
cout << numbers[i] << " has " << len[i] << " letters.\n";
}
// 析构交给 vector 处理
return 0;
}
// @ output: one has 3 letters.
// @ two has 3 letters.
// @ three has 5 letters.
// @ four has 4 letters.
// @ five has 4 letters.

《STL源码剖析》 – P456 - P460

STL之仿函数实现详解 <-- 例子来源

C++之ptr_fun、mem_fun 和 mem_fun_ref


5 参考资料

《STL源码剖析》

STL之仿函数实现详解

C++之ptr_fun、mem_fun 和 mem_fun_ref

MiniSTL / Function 部分

MiniSTL / Iterator 部分

MiniSTL / SequenceContainers / queue,stack 部分



----------- 本文结束 -----------




0%