C++的模板其实是个挺纠结的东西,用的不好的话,编译的一堆错误够你调到崩溃,但要是用的好呢,又确实非常方便,我们来看看
一.获取数组长度
比如
int arr[10];
怎么获取 arr 的长度呢? 最简单的代码:
uint32_t count = sizeof(arr) / sizeof(arr[0]);
但是这样也带来一个问题,万一是个新手程序员:
int *p = arr;
uint32_t count = sizeof(p) / sizeof(p[0]);
就有问题了…… 那么有没有办法,有一种安全的方法,当发现传入的是指针的时候,自动编译报错呢? 有的,模板里面可以推导出数组的长度。 所以我们可以使用如下代码
template <typename T, size_t N>
size_t arrarysize(T (&array)[N]) { return N; }
这样,当传入指针的时候,编译就会报错了。 而同时你肯定也能看出,我们甚至能指定只能传入数组长度为固定某数字的数组了,怎么做我就不用讲了吧?
二.切片函数
python中的切片函数真是令人怀念,并且即使传入的参数超过长度也不会崩溃,可是C++里面则就会出现问题,所以通常我们要把一个容器的数据做切片时,代码如下:
vector<int> src;
vector<uint32_t> dst;
uint32_t index;
uint32_t count;
vector<uint32_t>::iterator it_begin = src.begin() + index;
vector<uint32_t>::iterator it_end = (it_begin + count) < src.end() ? (it_begin + count) : src.end();
dst.insert(dst.begin(), it_begin, it_end);
注: 如果直接如下调用,会导致取到end()之后多余的数据
dst.insert(dst.begin(), src.begin() + index, src.begin() + index + count)
其实这代码还是挺纠结,而且并不通用(各种类型的容器都要重复写代码),所以我们也可以用模板来优化一下,代码如下:
template <typename T, typename P>
int Cut2Part(T& src, uint32_t index, uint32_t count, P& dst)
{
typeof(src.begin()) it_begin = src.begin() + index;
typeof(src.begin()) it_end = (it_begin + count) < src.end() ? (it_begin + count) : src.end();
dst.insert(dst.begin(), it_begin, it_end);
return 0;
}
可以注意到代码中使用了typeof,这也是C++挺好用的一个特性。 所以无论是什么类型的容器,只要如下调用即可
vector<int> src;
list<uint32_t> dst;
Cut2Part(src, index, count, dst)
三.获取类名
当在使用模板,或者使用继承关系的类时,我们经常需要在打印Log时清楚的知道到底是哪个类的实例在执行。 所以我们可以用这个函数:
typeid(obj).name()
如果实在类实例内部:
typeid(*this).name()
OK,需要介绍的内容就是这样了~~ 说句后话,python的确要比C++方便很多,但是在C++中经常会有这样的情景:在经过长时间尝试之后,“哇,原来这样能实现!”其实也是很不错的过程~比如之前的另一个宏定义:
#ifndef foreach
#define foreach(container,it) \
for(typeof((container).begin()) it = (container).begin();it!=(container).end();++it)
#endif
cndj on #
typeof是编译器提供的吗? 好似没在标准里面看过, 不过用0x的auto应该也能实现相同的功能
Reply
Dante on #
GCC家族里有,MS那套很久没用了,不太清楚。。
Reply
fanhe on #
typeof 貌似不是 c++ 的东西吧? 只知道有 typeid.
c++ 是有很多技巧, 也相当复杂...
Reply
Dante on #
不知道gcc家族里特有的还是ms也有。。不过还是挺方便的。
Reply
Huang Yun on #
typeof 似乎不是标准,在C++11里面有auto和decltype
Reply
打工战士 on #
而同时你肯定也能看出,我们甚至能指定只能传入数组长度为固定某数字的数组了,怎么做我就不用讲了吧?
不明白……求教
Reply
Dante on #
T (&array)[N]
这里的N写为固定的值就可以啦~
Reply
打工战士 on #
谢谢!
刚刚用gdb看了一下,数组名作为参数传进arraysize的时候,那个参数N就被初始化成数组的大小了。那么固定数组也是一样的道理了。
只是还有一个地方不太明白,参数N是怎么被初始化成数组size的呢?
Reply
Dante on #
这是C++的模板推导~
Reply
oldman on #
for_each 迭代那个例子可以使用 c++11中的auto 来推演类型(vs2010与gcc现在都已经支持)
不过既然都c++11了,那就干脆就用新版的for语法了(说新,其实其他语言都已经这么干了)(vs2010不支持,2012没试过-xp装不上。。)
<pre lang="cpp" line="1">
for( auto &x:container) {
.....
}
</pre>
或者你如果足够蛋疼可以试试Boost.Foreach
Reply
oldman on #
呃。。忘记给&&转义了。。
看下这里吧 http://en.wikipedia.org/wiki/C%2B%2B11#Range-based_for-loop
Reply
yafei.zhang@langtaojin.com on #
Cut2Part这个函数不是C++的风格
应该接受迭代器为参数的
Reply
yafei.zhang@langtaojin.com on #
typeof也只是GCC的扩展.
你最后一个例子为什么不去看看BOOST_FOREACH是如何实现的.
腾讯的不合格C++工程师真多
Reply
Dante on #
只针对你最后一句话。
我实在不理解,你是否一定要用这种说话方式来找自信呢?
Reply
yafei.zhang@langtaojin.com on #
我呆过, 知道情况, 一把一把的不合格的
Reply
Dante on #
第一,我无法理解你所谓的合不合格的标准
第二,我不知道你有没有判断别人是否合格的资格
第三,就做人来说,我觉得你沟通的方式有些问题
本博不想有这些无谓的争吵,有一争高下之心,大可绕道。
Reply
yafei.zhang@langtaojin.com on #
就事论事, 没必要吵.
那你觉得你这篇文章里的哪一个piece写的比较精彩呢?
Reply
yafei.zhang@langtaojin.com on #
如果我的语言打击到你, 我表示道歉.
我只是觉得有更优雅通用的方式, 没必要像你这样写的这么憋屈.
Reply
Dante on #
呵呵,本来我就不认同,怎么会受打击。
同样,优雅通用与否,憋屈与否也是见仁见智。
所以,你发表你的看法我没有意见,但是带有人身攻击的词语,这里不欢迎。
Reply
yafei.zhang@langtaojin.com on #
说了点事实就成攻击了. 来点真东西.
我提几个具体的意见给你的Cut2Part函数,免得一些纸上谈兵.你自己看看是不是更优雅通用了:
1.uint32_t不是C++标准中的,是C99中中的内容, 如果拿不准, uint32_t可以作为第三个模板参数,交给编译器去处理这个类型.
2.函数返回值的意义? 如果没有意义, 那为什么还要返回?
3.typeof也不是C++标准支持的, 是GCC扩展. 如果你不知道迭代器所指元素的类型, 可以用std::iterator_traits::value_type将其萃取出来, 但同时要求你所传入的参数不是一个容器, 而是一对迭代器.(即便传入容器, 也可以用typename P::iterator作为其迭代器)
4.你的容器所支持的迭代器如果不是随机访问迭代器, src.begin() + index;这样的操作是编译不过的, 可以使用std::advance将迭代器前进. 同样, 迭代器的小于比较也不是都支持的.
Reply
Zind on #
这位朋友,我实在看不下去了……
博主发文,是为了交流技术,分享心得……你在这里大放厥词,是为了砸场子么?
我姑且承认你是大牛,态度也不至于这么嚣张吧?如果认为这里太弱智,大可绕道。
Reply
Dante on #
感谢zind的支持~
yarfei,技术交流本身是件开心的事,何必这么浓的火药味。。
Reply
yafei.zhang@langtaojin.com on #
hi, 是你自己把火药味弄浓了, 我说的关于tx的事情都是我亲身体会. 我以前是在tx bj的. 不是专门针对你.
Reply
Dante on #
OK,那就休战吧。
Reply
yafei.zhang@langtaojin.com on #
取决于你的态度, 我一直都没有认为是战斗啊.
Reply
yafei.zhang@langtaojin.com on #
如果你对C++ STL了解充分, 完全还可以这样写, 比专门写一个函数简洁多了...
哪种好, 你自己可以比较一下.
#include
#include
#include
#include
int main()
{
std::vector src;
std::list dst;
size_t index = 0, count = 0;
// ...
//Cut2Part(src, index, count, dst);
//等价于
if (src.size() > index + count)
std::copy(src.begin()+index, src.end()+index+count, std::front_inserter(dst));
return 0;
}
Reply
Dante on #
yafei,没有人质疑你的能力,而是在说交流的态度,如果你只是想证明你更强,好吧,你赢了。
Reply
Zind on #
我也来班门弄斧一个:
// initialize elements of an array to 0
template void init_array(T (&array) [N])
{
for (size_t i = 0; i != N; ++i)
{
array[i] = 0;
}
return ;
}
Reply
Zind on #
呃……我不知道怎么发帖啊,那一对尖括号似乎是被转义掉了……
template 里面应该是有 typename T, size_t N
Reply
Dante on #
可以用pre标签哈,这个页面最上面有介绍:
http://www.vimer.cn/index.php/%E7%95%99%E8%A8%80
Reply
Dante on #
模板推导,我也很喜欢用,哈哈
Reply
Zind on #
博主别跟 ls 的某某一般见识。
它既然知道你是哪家公司的,应该是关注你博客有些时间了,肯定也读过你的不少博文。无论它从你的博客中是否学到了东西,或者学到了多少,这样对待一个知识产出者,都是无法接受的。
Reply
yafei.zhang@langtaojin.com on #
是, 我是学习VIM的, 我是VIM菜鸟.
互相取长补短, 他的C++水平是不好, 远远差于他的VIM水平啊.
Reply
编译点滴 on #
据说软件工程中有专门研究如何更高效的利用C++模板,可以参考下面两本书:
http://www.amazon.com/Core-C-Software-Engineering-Approach/dp/0130857297 和
http://www.amazon.com/Programming-Language-Pragmatics-Third-Michael/dp/0123745144/ref=sr_1_1?s=books&ie=UTF8&qid=1325165461&sr=1-1
Reply
tecbbs on #
请教博主用的代码高亮插件是不是wp-syntax?
我的wordpress3.3.1用wp-syntax有点问题,下面的文章
http://zhixing.tecbbs.com/archives/2012/02/18/241
<pre lang="cpp" line="1">
#include
using namespace std;
int main(){
}</pre>
我的将显示成了<和&gt:
Reply
Dante on #
很奇怪。。我有个朋友也说有这个问题,但是我自己用确实就没问题。。至今也不明白原因。。
Reply
tecbbs on #
我找到原因了,是我同时开了wp-syntaxhighlighter,关了就好了
Reply
hehe on #
其实作为一个学习者,我最喜欢出现像yafei.zhang这样的大牛来对我炮轰,要知道敢炮轰别人的,那都是有两把刷子的,如果你一旦虚心向炮轰我们的大牛请教,你的知识和见识会瞬间爬上一个高境界,这是求之不得的机会,所以我觉得博主应该赶紧对这些大牛表示感激涕零啊。而不是用凡夫俗子的观念来指责大牛的态度,大牛人家的自信和高傲是建立在扎实的学习之上的,不信你去挑挑大牛的代码的刺,人家一定对你感激,就算你骂大牛傻逼但是给出更牛逼的解答,大牛没准会和你做朋友。
就这个大牛对你的代码点评来说,你的C++代码确实写得像一坨屎。人家大牛的方案的确更为纯粹,这其实是高人指点你。所以如果真的是虚怀若谷的话,何必介意大牛的语气呢。
Reply