0
点赞
收藏
分享

微信扫一扫

C++ 泛型算法学习笔记(equal, accumulate, back_iterator, pair)


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表达式定义其他的二元判断符:

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

在不传入第四个参数的情况下,默认是使用二元操作符+。当我我们使用新的二元操作符后,返回值自然受到影响。

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类的对象指针,通过这个对象指针调用=操作符,就能完成元素的插入。
应用:

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函数:

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

可以测试:

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;
}


举报

相关推荐

0 条评论