equal
equal是区间比较算法
原型为:
template <class _InputIterator1, class _InputIterator2>
inline _LIBCPP_INLINE_VISIBILITY
bool
equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2)
{
typedef typename iterator_traits<_InputIterator1>::value_type __v1;
typedef typename iterator_traits<_InputIterator2>::value_type __v2;
return _VSTD::equal(__first1, __last1, __first2, __equal_to<__v1, __v2>());
}
template <class _InputIterator1, class _InputIterator2, class _BinaryPredicate>
inline _LIBCPP_INLINE_VISIBILITY
bool
equal(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __pred)
{
for (; __first1 != __last1; ++__first1, (void) ++__first2)
if (!__pred(*__first1, *__first2))
return false;
return true;
}
一般地,我们给equal传入三个参数即可,前两个分别是区间一的left迭代器和right迭代器,最后一个是区间二的left迭代器。从函数原型可以看出,区间二的范围大于等于区间一才有可能得到true。
明白了这层原理,我们可以设计自己的数据类型,并自定义equal,比如:
struct _point{
int x;
int y;
_point():x(0), y(0) { }
_point(int x_,int y_):x(x_), y(y_) { }
friend _point operator + (const _point p1, const _point p2){
_point p(p1);
p.x = p.x + p2.x;
p.y = p.y + p2.y;
return p;
}
friend ostream& operator << (ostream &out,const _point p){
out<<"("<<p.x<<" , "<<p.y<<")";
return out;
}
friend bool operator == (const _point &p1, const _point &p2){
return p1.x == p2.x && p1.y == p2.y;
}
};
int main()
{
_point p[] = {{0,0},{1,1},{2,2}};
cout<<equal(p,p+2,p)<<endl;
return 0;
}
或者使用lambda表达式定义其他的二元判断符:
cout<<equal(p+1,p+2,p+2,[](const _point p1,const _point p2){
return p1.y && p2.y && p1.x/p1.y == p2.x/p2.y;
})<<endl;
借助equal,我们可以方便的判断回文字符串,比如:
bool isPalindrome(const string str){
return equal(str.begin(),str.begin()+str.size()/2,str.rbegin());
}
int main()
{
cout<<isPalindrome("abcba")<<endl;
cout<<isPalindrome("jordan")<<endl;
return 0;
}
accumulate
accumulate函数定义在numeric头文件中,用于计算一段范围内的元素之和。
函数原型为:
template <class _InputIterator, class _Tp, class _BinaryOperation>
inline _LIBCPP_INLINE_VISIBILITY
_Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init, _BinaryOperation __binary_op)
{
for (; __first != __last; ++__first)
__init = __binary_op(__init, *__first);
return __init;
}
在不传入第四个参数的情况下,默认是使用二元操作符+。当我我们使用新的二元操作符后,返回值自然受到影响。
struct _point{
int x;
int y;
_point():x(0), y(0) { }
_point(int x_,int y_):x(x_), y(y_) { }
friend _point operator + (const _point p1, const _point p2){
_point p(p1);
p.x = p.x + p2.x;
p.y = p.y + p2.y;
return p;
}
friend ostream& operator << (ostream &out,const _point p){
out<<"("<<p.x<<" , "<<p.y<<")";
return out;
}
};
int main()
{
vector<_point> vp;
vp.push_back(_point(1,1));
vp.push_back(_point(2,2));
vp.push_back(_point(3,3));
cout<<accumulate(vp.begin(),vp.end(),_point(0,0))<<endl;
cout<<accumulate(vp.begin(),vp.end(),_point(0,0),[](const _point p1, const _point p2){
_point p(p1);
p.x = p.x - p2.x;
p.y = p.y - p2.y;
return p;
})<<endl;
return 0;
}
第二种计算使用了开发者lambda表达式定义的匿名二元函数。
注意:如果直接在结构体中定义operator -
,然后再使用:cout<<accumulate(vp.begin(),vp.end(),_point(0,0), -)<<endl;
编译器报错,不认识这样的表达式。
back_iterator
back_iterator返回对象的地址。
template <class _Container>
inline _LIBCPP_INLINE_VISIBILITY
back_insert_iterator<_Container>
back_inserter(_Container& __x)
{
return back_insert_iterator<_Container>(__x);
}
// ==>
_LIBCPP_INLINE_VISIBILITY explicit back_insert_iterator(_Container& __x) : container(_VSTD::addressof(__x)) {}
// ==>
template <class _Tp>
inline _LIBCPP_NO_CFI _LIBCPP_INLINE_VISIBILITY
_Tp*
addressof(_Tp& __x) _NOEXCEPT
{
return reinterpret_cast<_Tp *>(
const_cast<char *>(&reinterpret_cast<const volatile char &>(__x)));
}
// operator = 调用了容器的push_back函数。
_LIBCPP_INLINE_VISIBILITY back_insert_iterator& operator=(const typename _Container::value_type& __value_)
{container->push_back(__value_); return *this;}
整个过程:back_iterator将容器对象地址转换成back_insert_iterator类的对象指针,通过这个对象指针调用=操作符,就能完成元素的插入。
应用:
string str;
str.push_back('1');
auto it = back_inserter(str);
*it = '2';
cout<<str<<endl; //12
操作符是一个特殊的函数,我们的*it = '2';
还可以这样写:*it = (it.operator =('2'));
据此,我们还能将back_iterator和fill_n搭配使用,写出另类的append函数:
string str;
str.push_back('1');
fill_n(back_inserter(str),10,'0');
cout<<str<<endl; //10000000000
pair
查看了pair结构体的源码实现C++ pair源码,模拟它写了一个三元组结构体treble:
template<typename T1, typename T2, typename T3>
struct treble {
T1 first;
T2 second;
T3 third;
treble(): first(),second(),third() {}
treble(const T1 &__first, const T2 &__second, const T3 &__third){
first = __first; second = __second; third = __third;
}
treble& operator = (const treble &another){
this->first = another.first;
this->second = another.second;
this->third = another.third;
return *this;
}
template <typename T>
void basic_swap(T &t1, T &t2){
T t = t1;
t1 = t2;
t2 = t;
}
void swap(treble &another){
basic_swap(first,another.first);
basic_swap(second,another.second);
basic_swap(third,another.third);
}
friend ostream & operator <<(ostream &out, const treble &ins){
out<<"("<<ins.first<<", "<<ins.second<<", "<<ins.third<<")";
return out;
}
};
template<typename T1, typename T2, typename T3>
inline _LIBCPP_INLINE_VISIBILITY
treble<T1,T2,T3>
make_treble(const T1 &__first, const T2 &__second, const T3 &__third)
{
return treble<T1, T2, T3>(__first, __second, __third);
}
可以测试:
int main()
{
treble<int,string,double> ins = make_treble(1,string("one"),1.00);
cout<<ins<<endl;
treble<int,string,double> ano;
ano.swap(ins);
cout<<"after swap:\n";
cout<<ano<<endl;
cout<<ins<<endl;
return 0;
}