如果这篇博客帮助到你,可以请我喝一杯咖啡~
CC BY 4.0 (除特别声明或转载文章外)
一 特性 Traits
假设给定一个数组,计算数组中所有元素的和:
template <typename T>
inline T
Sigma(const T* start, const T* end)
{
T total = T();
while(start != end)
{
total += *start;
start++;
}
return total;
}
当我们使用 char
类型调用模板函数时:
char arr2[3] = {'a', 'b', 'c'};
cout << (int)Sigma(arr2, arr2 + 3) << endl;
发现输出的是 38,并不是 a,b,c
ASCII 码值的和,这是因为 char 类型最大存储 127,而 a,b,c
的 ASCII 码值超过了 char
类型的最大存储量,导致超出的部分被截断,只保留后 8 字节的信息。
同理 int 和其他类型也可能发生这种越界情况!这种情况应该怎么办?
解决的办法就是为每个 Sigma 函数参数类型分别创建一种关联,关联的类型就是用来存储 Sigma 结果的类型。
这种关联可以看作是 Sigma 函数的一种特性,因此 SIgma 函数的返回值的类型就叫做 T 的 trait
Traits
可以实现为模板类,而关联则是针对每个具体类型 T 的特化。
class SigmaTraits {};
template <>
class SigmaTraits<char>
{
public:
typedef int ReturnType;
};
template <>
class SigmaTraits<short>
{
public:
typedef int ReturnType;
};
template <>
class SigmaTraits<int>
{
public:
typedef long ReturnType;
};
template <>
class SigmaTraits<float>
{
public:
typedef double ReturnType;
};
修改函数 Sigma 的返回值类型:
template <typename T>
inline typename SigmaTraits<T>::ReturnType
Sigma(const T* start, const T* end)
{
typename SigmaTraits<T>::ReturnType total = T();
while(start != end)
{
total += *start;
start++;
}
return total;
}
调用端:
int main()
{
int arr[3] = {1, 2, 3};
char arr2[3] = {'a', 'b', 'c'};
typename SigmaTraits<char>::ReturnType sum = Sigma(arr2, arr2 + 3);
cout << sum << endl;
return 0;
}
二 迭代器 iterator
迭代器是泛化的指针
迭代器本身是一个对象,指向另一个(可迭代的)对象
迭代器是 STL 算法和容器的接口,它解耦算法和容器
容器只要提供一种方式,可以让迭代器访问容器元素
template<class _Init, class _Ty>
inline _Init find(_Init first, _Init last, const _Ty& val)
{
for(; first != last; ++first)
if(*first == val)
return first;
return first;
}
调用:
int main()
{
vector<int> v{2, 3, 4};
list<int> l{2, 3, 4};
deque<int> d{2, 3, 4};
int target = 3;
vector<int>::iterator vi = find(v.begin(), v.end(), target);
list<int>::iterator li = find(l.begin(), l.end(), target);
deque<int>::iterator di = find(d.begin(), d.end(), target);
cout << "vector : " << *vi << endl;
cout << "list : " << *li << endl;
cout << "deque : " << *di << endl;
return 0;
}
三 容器 Container
1、vector
数据结构和操作与 array
类似,内存中的表现是一段 地址连续 的空间。与 array
不同的是,vector
支持动态空间大小调整。
创建
访问
operator[]
提供类似数组的访问方式,不做边界检查,可能越界访问,但是效率较高at()
进行边界检查,越界抛出异常,效率不如operator[]
删除
clear()
清除整个vector
。注意:vector 容量不保证改变,不保证reallocation
。此函数的替代写法:vector<int> x; // ... vector<int>().swap(x);
pop_back()
尾删。vector
的size
减 1,调用被删除元素析构。由于不做范围检查,容器为空时删除可能造成程序崩溃。erase()
删除 vector 中某一位置的元素。用法 1:删除
iterator
指定位置的元素std::vector<int>::const_iterator it = v.begin(); v.erase(it + 1);
用法 2:通过某一条件函数(返回
true/false
)找到 vector 中要删除的元素。以remove_if()
为例
iterator erase(const_iterator1, const_iterator2)
删除 [const_iterator1, const_iterator2)
区间内的所有元素
#include <algorithm>
struct ContainString : public unary_function<string, bool>
{
ContainString(const string& str) : str_match(str) {}
bool operator()(const string& str2match) const
{
return str2match.find(str_match) != -1;
}
string str_match;
};
int main()
{
vector<string> v;
v.push_back("I love C++");
v.push_back("I love you");
v.push_back("C++ doesn't love me");
// 删除所有 ContainString(str) 返回值为 true 的元素
// 传入参数时的 ContainString("C++") 调用的是 ContainString 的构造函数
// remove_if 内的函数调用是 operator()
v.erase( remove_if(v.begin(), v.end(), ContainString("C++")),
v.end()
);
for(auto s : v)
cout << s << endl;
}
forward_iterator remove_if(forward_iterator first, forward_iterator last, pred)
remove_if
并没有删除任何元素,只是改变了元素的位置。将满足删除条件的元素放到 last
之前。这样说可能不够具体,详细的可以看代码:
template<typename _ForwardIterator, typename _Predicate>
inline _ForwardIterator
remove_if(_ForwardIterator __first, _ForwardIterator __last,
_Predicate __pred)
{
return std::__remove_if(__first, __last,
__gnu_cxx::__ops::__pred_iter(__pred));
}
template<typename _InputIterator, typename _Predicate>
inline _InputIterator
__find_if(_InputIterator __first, _InputIterator __last,
_Predicate __pred, input_iterator_tag)
{
while (__first != __last && !__pred(__first))
++__first;
return __first;
}
template<typename _ForwardIterator, typename _Predicate>
_ForwardIterator
__remove_if(_ForwardIterator __first, _ForwardIterator __last,
_Predicate __pred)
{
__first = std::__find_if(__first, __last, __pred);
if (__first == __last)
return __first;
_ForwardIterator __result = __first;
++__first;
for (; __first != __last; ++__first)
if (!__pred(__first))
{
*__result = _GLIBCXX_MOVE(*__first);
++__result;
}
return __result;
}
移动元素的操作在 __remove_if
中:
for (; __first != __last; ++__first)
if (!__pred(__first))
{
// __result 位置为待删除元素,直接用不删除的元素覆盖要删除的元素
// #define _GLIBCXX_MOVE(__val) std::move(__val)
// 赋值时使用右移版本的 operator=
*__result = _GLIBCXX_MOVE(*__first);
++__result;
}
2、list
创建
删除
clear()
:内部调用erase(begin(), end())
pop_back()
尾删pop_front()
头删remove()
删除 list 指定值元素erase()
同样是两个版本,删除迭代器指定位置的元素,删除迭代器指定区间的元素
与 vector 类似:
list<string> l{ string("C++ love me"), string("who love me"), string("nobody love me") };
//l.remove_if(ContainString("C++"));
l.erase(remove_if(l.begin(), l.end(), ContainString("C++")), l.end());
连接
splice
l1.splice(iterator, l2) 将 l2 所有元素加入 l1 的 iterator 位置并删除 l2 所有元素
list<string> l{ string("C++ love me"), string("who love me"), string("nobody love me") };
list<string> l2 { string("everyone loves me!"), string("I'm beautiful") };
l.splice(l.begin(), l2);
for(auto& e : l)
{
cout << e << endl;
}
cout << "==================" <<endl;
for(auto& e : l2)
{
cout << e << endl;
}
everyone loves me!
I'm beautiful
C++ love me
who love me
nobody love me
==================
l3.splice(l3.begin(), l, it1) 将 l
中迭代器 it1
所指向的元素加入 l3
的迭代器 l3.begin()
所指向的元素前
list<string> l{ string("C++ love me"), string("who love me"), string("nobody love me") };
list<string> l2 { string("everyone loves me!"), string("I'm beautiful") };
list<string> l3;
auto it1 = l.begin();
advance(it1, 1);
l3.splice(l3.begin(), l, it1);
for(auto& e : l)
{
cout << e << endl;
}
cout << "==================" <<endl;
for(auto& e : l3)
{
cout << e << endl;
}
C++ love me
nobody love me
==================
who love me
l.splice(l.begin(), l, it1, l.end()) 将 l
的 [it1, l.end())
范围内的元素加入 l
的 l.begin()
指示的位置前
list<string> l{ string("C++ love me"), string("who love me"), string("nobody love me") };
auto it1 = l.begin();
advance(it1, 1);
l.splice(l.begin(), l, it1, l.end());
for(auto& e : l)
{
cout << e << endl;
}
who love me
nobody love me
C++ love me
3、map\multimap
template < class Key, // map::key_type
class T, // map::mapped_type
class Compare = less<Key>, // map::key_compare
class Alloc = allocator<pair<const Key,T> > // map::allocator_type
> class map;
- key 不可修改,不能重复
- key 具有
operator<
行为 - 可自定义排序函数,默认采用 less
struct Employee
{
Employee() {}
Employee(const string& str) : m_name(str) {}
string m_name;
};
template<typename T>
struct CmpById : binary_function<T, T, bool>
{
bool operator()(const T& left, const T& right) const
{
return left > right;
}
};
int main()
{
map<int, Employee, CmpById<int>> m;
m.insert( make_pair(3, Employee("none")) );
m.insert( make_pair(1, Employee("wxc")) );
m.insert( make_pair(2, Employee("hc")) );
for(auto& e : m)
{
cout << e.second.m_name << endl;
}
return 0;
}
none
hc
wxc
multimap
允许 key 重复
int main()
{
multimap<int, Employee, CmpById<int>> m;
m.insert( make_pair(3, Employee("none")) );
m.insert( make_pair(1, Employee("wxc")) );
m.insert( make_pair(2, Employee("hc")) );
m.insert( make_pair(2, Employee("hc")) );
cout << m.count(2) << endl;
return 0;
}
2
4、set\multiset
template < class T, // set::key_type/value_type
class Compare = less<T>, // set::key_compare/value_compare
class Alloc = allocator<T> // set::allocator_type
> class set;
- key 不可修改,不能重复。
- key 和 value 相同
- 对象具有
operator<
行为 - 可自定义排序函数,默认采用 less
set_union(s.begin(), s.end(), s2.begin(), s2.end(), ii, CmpById< Employee >());
并集
struct Employee
{
Employee() {}
Employee(const string& str, const int age) : m_name(str), m_age(age) {}
bool operator<(const struct Employee& right) const
{
return m_age < right.m_age;
}
string m_name;
int m_age;
};
template<typename T>
struct CmpById : binary_function<T, T, bool>
{
bool operator()(const T& left, const T& right) const
{
return !(left < right);
}
};
set<Employee, CmpById<Employee>> s;
s.insert(Employee("wxc", 22));
s.insert(Employee("hc", 28));
s.insert(Employee("wxxc", 0));
set<Employee, CmpById<Employee>> s2;
s2.insert(Employee("jack", 21));
s2.insert(Employee("john", 24));
s2.insert(Employee("shepard", 30));
set<Employee, CmpById<Employee>> dest;
insert_iterator<set<Employee, CmpById<Employee>>> ii(dest, dest.begin());
set_union(s.begin(), s.end(), s2.begin(), s2.end(), ii, CmpById<Employee>());
for(auto e : dest)
{
cout << e.m_age << " " << e.m_name << endl;
}
30 shepard
28 hc
24 john
22 wxc
21 jack
0 wxxc
set_intersection(s.begin(), s.end(), s2.begin(), s2.end(), ii, CmpById< Employee >());
交集
template<typename T>
struct CmpById : binary_function<T, T, bool>
{
bool operator()(const T& left, const T& right) const
{
return (left < right);
}
};
set<Employee, CmpById<Employee>> s;
s.insert(Employee("wxc", 22));
s.insert(Employee("hc", 28));
s.insert(Employee("wxxc", 0));
for(auto e : s)
{
cout << e.m_age << " " << e.m_name << endl;
}
set<Employee, CmpById<Employee>> s2;
s2.insert(Employee("wxc", 21));
s2.insert(Employee("wxc", 22));
s2.insert(Employee("hc", 28));
for(auto e : s2)
{
cout << e.m_age << " " << e.m_name << endl;
}
set<Employee, CmpById<Employee>> dest;
insert_iterator<set<Employee, CmpById<Employee>>> ii(dest, dest.begin());
set_intersection(s.begin(), s.end(), s2.begin(), s2.end(), ii, CmpById<Employee>());
注意仿函数对象对 operator()
的重载不能写成这样:
template<typename T>
struct CmpById : binary_function<T, T, bool>
{
bool operator()(const T& left, const T& right) const
{
return !(left < right);
}
};
不能对结果取反,否则交集会算错。
因为 union_intersection
的判断原理是这样的:对于 set1
的元素 s1
和 set2
的元素 s2
,如果 ( comp(s1, s2) == false ) && ( comp(s2, s1) == false )
则认为 s1 == s2
。若写成上面错误的形式,本来 comp(s1, s2) == false
取反成 true
了。
源代码如下:
template<typename _InputIterator1, typename _InputIterator2,
typename _OutputIterator,
typename _Compare>
_OutputIterator
__set_intersection(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _InputIterator2 __last2,
_OutputIterator __result, _Compare __comp)
{
while (__first1 != __last1 && __first2 != __last2)
if (__comp(__first1, __first2))
++__first1;
else if (__comp(__first2, __first1))
++__first2;
else
{
*__result = *__first1;
++__first1;
++__first2;
++__result;
}
return __result;
}
set_difference(s.begin(), s.end(), s2.begin(), s2.end(), ii, CmpById< Employee >());
差集
set<Employee, CmpById<Employee>> s;
s.insert(Employee("wxc", 22));
s.insert(Employee("hc", 28));
s.insert(Employee("wxxc", 0));
set<Employee, CmpById<Employee>> s2;
s2.insert(Employee("wxc", 21));
s2.insert(Employee("wxc", 22));
s2.insert(Employee("hc", 28));
set<Employee, CmpById<Employee>> dest;
insert_iterator<set<Employee, CmpById<Employee>>> ii(dest, dest.begin());
// s - s2
set_difference(s.begin(), s.end(), s2.begin(), s2.end(), ii, CmpById<Employee>());
// 0 wxxc
如果在 set_difference
中改变参数的顺序,则调用结果不同:
// s2 - 2
set_difference(s2.begin(), s2.end(), s.begin(), s.end(), ii, CmpById<Employee>());
//21 wxc
set_difference()
的原理是:对于有序的(排序规则相同)集合 set1 和 set2, set1
的元素 s1
, set2
的元素 s2
,如果 comp(s1, s2) == true
则认为 s1
不存在于 s2
template<typename _InputIterator1, typename _InputIterator2,
typename _OutputIterator,
typename _Compare>
_OutputIterator
__set_difference(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _InputIterator2 __last2,
_OutputIterator __result, _Compare __comp)
{
while (__first1 != __last1 && __first2 != __last2)
// first1 不存在于 first2
if (__comp(__first1, __first2))
{
*__result = *__first1;
++__first1;
++__result;
}
// first2 不存在于 first1
else if (__comp(__first2, __first1))
++__first2;
// 共同元素
else
{
++__first1;
++__first2;
}
return std::copy(__first1, __last1, __result);
}
对于 Employee
对象,真正参与比较的只有 m_age
字段:
struct Employee
{
Employee() {}
Employee(const string& str, const int age) : m_name(str), m_age(age) {}
bool operator<(const struct Employee& right) const
{
return m_age < right.m_age;
}
string m_name;
int m_age;
};
template<typename T>
struct CmpById : binary_function<T, T, bool>
{
bool operator()(const T& left, const T& right) const
{
return left < right;
}
};
所以只有 m_age
是真正的 key,其他的字段并不是 key。但是如果想要修改其他字段:
auto it = s.find(Employee("wxc", 22));
if(it != s.end())
it->m_name = "123";
这样的修改是非法的!
若要修改非 key 字段,可通过如下手段:
auto it = s.find(Employee("wxc", 22));
if(it != s.end())
const_cast<Employee&>(*it).m_name = "123";
for(auto e : s)
cout << e.m_name << endl;
wxxc
123
hc
注意一定要将 *it
转换为引用类型,不然修改的是临时对象的值!
if(it != s.end())
((Employee)(*it)).m_name = "123";
set 中的元素并没有修改!上面的代码等价于:
Employee tmp(*it);
tmp.m_name = "123";
四 仿函数 Functors
仿函数又称函数对象(function object),作用相当于一个函数指针
回顾之前对 remove_if
的调用:
remove_if(v.begin(), v.end(), ContainString("C++"));
ContainString
一般实现为一个 struct
或 class
,所以 ContainString()
就是创建一个 ContainString
对象。remove_if
中传入了一个 ContainString
临时对象并调用其构造函数,参数为字符串 "C++"
示例 1:
template<typename T>
struct Less : binary_function<T, T, bool>
{
bool operator()(const T& left, const T& right) const
{
return left < right;
}
};
int main()
{
Less<int> less;
cout << less(10, 3) << endl;
// boolalpha 将布尔类型的值字符串化
cout << std::boolalpha << less(3, 10) << endl;
return 0;
}
0
true
实例 2 :使用 for_each()
struct PrintEmployee : unary_function<Employee&, void>
{
ostream& os;
explicit PrintEmployee(ostream& out) : os(out) {}
void operator()(const Employee& employee) const
{
os << employee.m_name << " " << employee.m_age << std::endl;
}
};
int main()
{
vector<Employee> employees{Employee("wxc", 22), Employee("hc", 28)};
// 对 [it1, it2) 区间的每个元素调用 PrintEmployee()
for_each(employees.begin(), employees.end(), PrintEmployee(cout));
return 0;
}
为什么要用仿函数而不是普通指针?
- 函数指针不能满足 STL 的抽象要求
- 函数指针无法和 STL 的其他组件交互
- 仿函数可作为模板实参用于定义对象的某种默认行为
set 默认以 less 作为元素的排序方式,两个不同排序方式的 set 无法进行赋值或判等!
set<int, less<int>> s_less1;
set<int, less<int>> s_less2;
set<int, greater<int>> s_greater;
s_less1 == s_less2; // ok
s_less1 == s_greater; // error
如果要用 set 存储自定义的类,自定义的类应满足可比较大小要求(重载 operator<
或operator>
等函数),如果使用 set
默认的 less
作为比较规则,则应该重载 operator<
函数
struct Employee
{
Employee() {}
Employee(const string& str, const int age) : m_name(str), m_age(age) {}
bool operator<(const struct Employee& right) const
{
return m_age < right.m_age;
}
string m_name;
int m_age;
};
template<typename _Tp>
struct less : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp& __x, const _Tp& __y) const
{ return __x < __y; }
};
五 仿函数适配器 Functor Adapters
仿函数适配器旨在将无法匹配的仿函数套接成可以匹配的类型
1、binder1st
给定一个数组 [0, 0, 0, 3, 2, 1]
,如何通过 std::not_equal_to
匹配得到第一个非零元素?一个可以想象的调用:
vector<int> v{0, 0, 0, 3, 2, 1};
find_if(v.begin(), v.end(), not_equal_to<int>(0));
但这样是行不通的,我们来看一下 not_equal_to
的实现:
template<typename _Tp>
struct not_equal_to : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp& __x, const _Tp& __y) const
{ return __x != __y; }
};
not_equal_to
没有单参构造,且是一个二元运算符!
int main()
{
vector<int> v{0, 0, 0, 3, 2, 1};
not_equal_to<int> net;
typename not_equal_to<int>::first_argument_type tar = 0;
std::binder1st<std::not_equal_to<int>> bind1(net, tar);
auto it = find_if(v.begin(), v.end(), bind1);
if(it != v.end())
cout << *it << endl;
return 0;
}
binder1st 实现
template<typename _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); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 109. Missing binders for non-const sequence elements
typename _Operation::result_type
operator()(typename _Operation::second_argument_type& __x) const
{ return op(value, __x); }
} _GLIBCXX_DEPRECATED;
_Operation
类型就是 not_equal_to<int>
,要寻找的目标 tar
绑定到了 value
上,作为 not_equal_to()
的第一参数,find_if
以此传入 vector
的每个元素作为 not_equal_to
的第二参数。
当 find_if
调用 binder1st
时:binder1st(*iterator)
实际调用的是 op(value, *iterator)
也就是 not_equal_to(tar, x)
x 为数组元素。
2、binder2nd
template<typename _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); }
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 109. Missing binders for non-const sequence elements
typename _Operation::result_type
operator()(typename _Operation::first_argument_type& __x) const
{ return op(__x, value); }
} _GLIBCXX_DEPRECATED;
和 binder1st
不同的是,binder2nd
的 op 参数顺序反过来了,op(x, target)
(binder1st
为 op(target, x)
)
3、mem_fun
适配对象成员函数
struct Employee
{
Employee() {}
Employee(const string& str, const int age) : m_name(str), m_age(age) {}
bool operator<(const struct Employee& right) const
{
return m_age < right.m_age;
}
void print()
{
cout << m_name << " " << m_age << endl;
}
string m_name;
int m_age;
};
int main()
{
vector<Employee> emp{Employee("wxc", 22), Employee("hc", 28)};
for_each(emp.begin(), emp.end(), &Employee::print); // error
return 0;
}
我们先来看一下 for_each
的实现:
template<typename _InputIterator, typename _Function>
_Function
for_each(_InputIterator __first, _InputIterator __last, _Function __f)
{
for (; __first != __last; ++__first)
__f(*__first);
return __f;
}
由于 for_each
的调用方式为 _f(*first)
,我们传入的函数指针是类的成员函数不能采用该方法调用,所以就需要一个适配器。这个适配器一定可以将 fun(obj)
的调用形式转变为 pobj->fun()
或 obj.fun()
然后我们来看 men_fun_ref
的实现:
template<typename _Ret, typename _Tp>
inline mem_fun_ref_t<_Ret, _Tp>
mem_fun_ref(_Ret (_Tp::*__f)())
{ return mem_fun_ref_t<_Ret, _Tp>(__f); }
调用 mem_fun_ref
时,传入一个函数指针,返回值为 _Ret
,参数为空。类类型为 _Tp
mem_fun_ref_t
实现:
template<typename _Ret, typename _Tp>
class mem_fun_ref_t : public unary_function<_Tp, _Ret>
{
public:
explicit
mem_fun_ref_t(_Ret (_Tp::*__pf)())
: _M_f(__pf) { }
_Ret
operator()(_Tp& __r) const
{ return (__r.*_M_f)(); }
private:
_Ret (_Tp::*_M_f)();
};
mem_fun
调用函数的方式则是通过指针,其他相同:
template<typename _Ret, typename _Tp>
class mem_fun_t : public unary_function<_Tp*, _Ret>
{
public:
explicit
mem_fun_t(_Ret (_Tp::*__pf)())
: _M_f(__pf) { }
_Ret
operator()(_Tp* __p) const
{ return (__p->*_M_f)(); }
private:
_Ret (_Tp::*_M_f)();
};
/// One of the @link memory_adaptors adaptors for member
/// pointers@endlink.
template<typename _Ret, typename _Tp>
class const_mem_fun_t : public unary_function<const _Tp*, _Ret>
{
public:
explicit
const_mem_fun_t(_Ret (_Tp::*__pf)() const)
: _M_f(__pf) { }
_Ret
operator()(const _Tp* __p) const
{ return (__p->*_M_f)(); }
private:
_Ret (_Tp::*_M_f)() const;
};
/// One of the @link memory_adaptors adaptors for member
/// pointers@endlink.
template<typename _Ret, typename _Tp>
class mem_fun_ref_t : public unary_function<_Tp, _Ret>
{
public:
explicit
mem_fun_ref_t(_Ret (_Tp::*__pf)())
: _M_f(__pf) { }
_Ret
operator()(_Tp& __r) const
{ return (__r.*_M_f)(); }
private:
_Ret (_Tp::*_M_f)();
};
/// One of the @link memory_adaptors adaptors for member
/// pointers@endlink.
template<typename _Ret, typename _Tp>
class const_mem_fun_ref_t : public unary_function<_Tp, _Ret>
{
public:
explicit
const_mem_fun_ref_t(_Ret (_Tp::*__pf)() const)
: _M_f(__pf) { }
_Ret
operator()(const _Tp& __r) const
{ return (__r.*_M_f)(); }
private:
_Ret (_Tp::*_M_f)() const;
};
/// One of the @link memory_adaptors adaptors for member
/// pointers@endlink.
template<typename _Ret, typename _Tp, typename _Arg>
class mem_fun1_t : public binary_function<_Tp*, _Arg, _Ret>
{
public:
explicit
mem_fun1_t(_Ret (_Tp::*__pf)(_Arg))
: _M_f(__pf) { }
_Ret
operator()(_Tp* __p, _Arg __x) const
{ return (__p->*_M_f)(__x); }
private:
_Ret (_Tp::*_M_f)(_Arg);
};
/// One of the @link memory_adaptors adaptors for member
/// pointers@endlink.
template<typename _Ret, typename _Tp, typename _Arg>
class const_mem_fun1_t : public binary_function<const _Tp*, _Arg, _Ret>
{
public:
explicit
const_mem_fun1_t(_Ret (_Tp::*__pf)(_Arg) const)
: _M_f(__pf) { }
_Ret
operator()(const _Tp* __p, _Arg __x) const
{ return (__p->*_M_f)(__x); }
private:
_Ret (_Tp::*_M_f)(_Arg) const;
};
/// One of the @link memory_adaptors adaptors for member
/// pointers@endlink.
template<typename _Ret, typename _Tp, typename _Arg>
class mem_fun1_ref_t : public binary_function<_Tp, _Arg, _Ret>
{
public:
explicit
mem_fun1_ref_t(_Ret (_Tp::*__pf)(_Arg))
: _M_f(__pf) { }
_Ret
operator()(_Tp& __r, _Arg __x) const
{ return (__r.*_M_f)(__x); }
private:
_Ret (_Tp::*_M_f)(_Arg);
};
/// One of the @link memory_adaptors adaptors for member
/// pointers@endlink.
template<typename _Ret, typename _Tp, typename _Arg>
class const_mem_fun1_ref_t : public binary_function<_Tp, _Arg, _Ret>
{
public:
explicit
const_mem_fun1_ref_t(_Ret (_Tp::*__pf)(_Arg) const)
: _M_f(__pf) { }
_Ret
operator()(const _Tp& __r, _Arg __x) const
{ return (__r.*_M_f)(__x); }
private:
_Ret (_Tp::*_M_f)(_Arg) const;
};
// Mem_fun adaptor helper functions. There are only two:
// mem_fun and mem_fun_ref.
template<typename _Ret, typename _Tp>
inline mem_fun_t<_Ret, _Tp>
mem_fun(_Ret (_Tp::*__f)())
{ return mem_fun_t<_Ret, _Tp>(__f); }
template<typename _Ret, typename _Tp>
inline const_mem_fun_t<_Ret, _Tp>
mem_fun(_Ret (_Tp::*__f)() const)
{ return const_mem_fun_t<_Ret, _Tp>(__f); }
template<typename _Ret, typename _Tp>
inline mem_fun_ref_t<_Ret, _Tp>
mem_fun_ref(_Ret (_Tp::*__f)())
{ return mem_fun_ref_t<_Ret, _Tp>(__f); }
template<typename _Ret, typename _Tp>
inline const_mem_fun_ref_t<_Ret, _Tp>
mem_fun_ref(_Ret (_Tp::*__f)() const)
{ return const_mem_fun_ref_t<_Ret, _Tp>(__f); }
template<typename _Ret, typename _Tp, typename _Arg>
inline mem_fun1_t<_Ret, _Tp, _Arg>
mem_fun(_Ret (_Tp::*__f)(_Arg))
{ return mem_fun1_t<_Ret, _Tp, _Arg>(__f); }
template<typename _Ret, typename _Tp, typename _Arg>
inline const_mem_fun1_t<_Ret, _Tp, _Arg>
mem_fun(_Ret (_Tp::*__f)(_Arg) const)
{ return const_mem_fun1_t<_Ret, _Tp, _Arg>(__f); }
template<typename _Ret, typename _Tp, typename _Arg>
inline mem_fun1_ref_t<_Ret, _Tp, _Arg>
mem_fun_ref(_Ret (_Tp::*__f)(_Arg))
{ return mem_fun1_ref_t<_Ret, _Tp, _Arg>(__f); }
template<typename _Ret, typename _Tp, typename _Arg>
inline const_mem_fun1_ref_t<_Ret, _Tp, _Arg>
mem_fun_ref(_Ret (_Tp::*__f)(_Arg) const)
{ return const_mem_fun1_ref_t<_Ret, _Tp, _Arg>(__f); }
最多只能带一个参数!
七 内存分配器 allocator
这部分内容在另一个博客详细讲解
八 其他
- 效率比手写循环高
- 代码可读性,可维护性更高
注意,下面这样写是不行的:
emp.swap(vector<Employee>()); // error
//! Non-const lvalue reference to type 'vector<...>' cannot bind to a temporary of type 'vector<...>'
vector<Employee>().swap(emp); // ok
我们来看一下 vector::swap()
的声明:
void swap(vector& __x) _GLIBCXX_NOEXCEPT
swap
参数为非 const 引用类型,第一种写法临时对象会作为参数。临时对象的引用得用 const
引用,所以只能用临时对象左右函数的第一参数,位于成员调用符号左侧
swap
函数的本质时交换了 vector
内的三个指针
void
swap(vector& __x) _GLIBCXX_NOEXCEPT
{
this->_M_impl._M_swap_data(__x._M_impl);
_Alloc_traits::_S_on_swap(_M_get_Tp_allocator(),
__x._M_get_Tp_allocator());
}
void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT
{
std::swap(_M_start, __x._M_start);
std::swap(_M_finish, __x._M_finish);
std::swap(_M_end_of_storage, __x._M_end_of_storage);
}