分享

第102讲 扩展标准库(1)

 佛法与智慧 2016-09-23

昨天我们说了一个日志记录器,该日志记录器的他可以保证我们要记录的东西会一个不少的记录下来,想必大家也看到了我们会在析构函数里面等待日志记录线程的返回,所以当我们关闭程序的时候不用担心是否有内容没有被记录下来,所以他的实用性还是挺高的。
ok,今天我们说另一个小工具,这个工具在处理一些复杂数据的时候会有一些意想不到的效果,不过这得和大家说一些,我是一个标准的标准库忠实者,所以我写程序基本都会优先考虑库,然后在世boost库,而接下来的东西我会借助标准库的东西进行扩展的。
既然是标准库的扩展,那么第一步我们可以先将标准库的东西再进行一些简化,当然这些简化只是为了我们在调试程序的时候方便使用一些。
C 的标准输出输入流为了简便都提供了一个操作符(<<)用来输出(>>)用来输入,所以为了简便,我们可以先将C 里面的标准容器都让它们带有这种流式操作,就比如:
//====================================
std::vector<int> v;
v<<1<<2<<3<<4.......; //将数据压入容器中
int a,b,c,d;
v>>a>>b>>c>>d;
//将容器中的元素从后到前依次提取

//======================================
让容器变得这么简便随便提供不了多大的好处,但是要是你习惯这样的编程习惯后你就会发现这样做其他也是挺好的,ok,那么第一步,我们先来将该功能实现。
要实现上面的功能大家第一步可能已经想到了,也许是下面这样:

//=====================================

template<class T>
inline std::vector<T>& operator<<(std::vector<T>& v, const T& value){
v.push_back(value);
return v;
}

template<class T>
inline std::vector<T>& operator>>(std::vector<T>& v, T& value){
if (v.empty()){
value = T();
}
else{
value = v.back();
v.pop_back();
}
return v;
}

//========================================

确实,我们可以这么实现,而且工作得挺好,如果我们想要操作的是list的话,那么我们再实现一个list版本的即可:

//========================================
template<class T>
inline std::list<T>& operator<<(std::list<T>& l, const T& value){
l.push_back(value);
return l;
}

template<class T>
inline std::list<T>& operator>>(std::list<T>& l, T& value){
if (l.empty()){
value = T();
}
else{
value = l.back();
l.pop_back();
}
return l;
}

//==========================================
ok,这是list的流式操作也出来了,那么如果容器是队列呢............嗯,就算全部写出来也不算多了,因为标准库里面的容器其实也就这么几个了,但是如果有很多呢......
好吧,不知道大家还能够想起以前给大家说的关于模板的一些高级技巧没,如果想不起,没关系,可以回头去看看,大概在90讲左右,如果都已经熟悉那就更好不过,因为我们可以使用更简单的方式来实现这种简便的操作,那就是使用模板的模板参数,首先我们可以肯定的知道不管是vector还是list,又或者是deque他们都有一个共同的特点,就是使用push_back来把数据压入容器,使用pop_back函数来将数据从后面弹出,所以我们只需要两个函数就能够完成对这三个标准容器的流式操作了,如下:

//==========================================
template<typename T,typename A,template<typename U,typename A1> class C>
C<T, A>& operator<<(C<T, A>& c, const T& value){
c.push_back(value);
return c;
}

template<typename T, typename A, template<typename U, typename A1> class C>
C<T, A>& operator>>(C<T, A>& c, T& value){
if (c.empty()){
value = T();
}
else{
value = c.back();
c.pop_back();
}
return c;
}

//==========================================

ok,使用模板就是这么方便,这里我们使用的是模板的模板参数这一技巧。下面是set的实现:

//===========================================

template<typename T, typename C, typename A, template<typename U, typename C1, typename A1> class S>
S<T, C, A>& operator<<(S<T, C, A>& c,const T& value){
c.insert(value);
return c;
}


template<typename T,typename C, typename A, template<typename U, typename C1,typename A1> class S>
S<T, C,A>& operator>>(S<T,C, A>& c, T& value){
if (c.empty()){
value = T();
}
else{
auto it = --c.end();
value = *(it);
c.erase(it);
}
return c;
}

//================================================
由于set和vector他们的操作不一样,所以写法稍微有些不一样,对于map倒是和set差不多的了:

//===============================================
template<typename K,typename V,typename C,typename A,
template<typename U,typename U1,typename C1,typename A1> class M>
M<K, V, C, A>& operator<<(M<K, V, C, A>& m, const std::pair<K, V>& p){
m.insert(p);
return m;
}

template<typename K, typename V, typename C, typename A,
template<typename U, typename U1, typename C1, typename A1> class M>
M<K, V, C, A>& operator>>(M<K, V, C, A>& m, std::pair<K, V>& p){
if (m.empty()){
p = std::make_pair(K(), V());
}
else{
auto it = --m.end();
p = *it;
m.erase(it);
}
return m;
}

//================================================

ok,到这里我们基本都对标准库一些常用的容器都进行了一次包装,那么接下来我们希望在调试程序的时候如果遇到一个容器,我们想要知道容器里面的是什么,为了方便,我们可能希望能够像操作基本类型一样的用流来操作容器,例如:
//=================================================
std::vector<int> v;
v << 1 << 2 << 3 << 4 << 5;
std::cout<<v<<std::endl;
//将容器里面的内容打印出来
//==================================================

要实现这个功能还是像上面一样简单,今天我们就用这个来做结尾,下一讲我们再继续:

//===================================================
//对vector,list deque的打印

template<typename T,typename A,template<typename U,typename A1> class C>
std::ostream& operator<<(std::ostream& os, const C<T, A>& c){
if (c.empty())
return os;
std::copy(c.begin(), --c.end(), std::ostream_iterator<T>(os, ','));
os << *(--c.end());
return os;
}

//==================================================

下面是对set的打印
//==================================================
template<typename T, typename C, typename A, template<typename U, typename C1, typename A1> class S>
std::ostream& operator<<(std::ostream& os, const S<T,C, A>& c){
if (c.empty())
return os;
std::copy(c.begin(), --c.end(), std::ostream_iterator<T>(os, ','));
os << *(--c.end());
return os;
}

//==================================================

对map的打印
//=================================================
template<typename K, typename V, typename C, typename A,
template<typename U, typename U1, typename C1, typename A1> class M>
std::ostream& operator<<(std::ostream& os, const M<K, V, C, A>& m){
if (m.empty())
return os;
std::for_each(m.begin(), m.end(), [&](std::pair<K, V> p){
os << p.first << ',' << p.second << ',';
});
return os;
}

//=================================================

ok,今天就到这里吧……

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多