最后更新于 .

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

 

Pingbacks

Pingbacks已打开。

Trackbacks

引用地址

评论

  1. cndj

    cndj on #

    typeof是编译器提供的吗? 好似没在标准里面看过, 不过用0x的auto应该也能实现相同的功能

    Reply

    1. Dante

      Dante on #

      GCC家族里有,MS那套很久没用了,不太清楚。。

      Reply

  2. fanhe

    fanhe on #

    typeof 貌似不是 c++ 的东西吧? 只知道有 typeid.
    c++ 是有很多技巧, 也相当复杂...

    Reply

    1. Dante

      Dante on #

      不知道gcc家族里特有的还是ms也有。。不过还是挺方便的。

      Reply

  3. Huang Yun

    Huang Yun on #

    typeof 似乎不是标准,在C++11里面有auto和decltype

    Reply

  4. 打工战士

    打工战士 on #

    而同时你肯定也能看出,我们甚至能指定只能传入数组长度为固定某数字的数组了,怎么做我就不用讲了吧?
    不明白……求教

    Reply

    1. Dante

      Dante on #

      T (&array)[N]

      这里的N写为固定的值就可以啦~

      Reply

      1. 打工战士

        打工战士 on #

        谢谢!
        刚刚用gdb看了一下,数组名作为参数传进arraysize的时候,那个参数N就被初始化成数组的大小了。那么固定数组也是一样的道理了。
        只是还有一个地方不太明白,参数N是怎么被初始化成数组size的呢?

        Reply

        1. Dante

          Dante on #

          这是C++的模板推导~

          Reply

  5. oldman

    oldman on #

    for_each 迭代那个例子可以使用 c++11中的auto 来推演类型(vs2010与gcc现在都已经支持)

    不过既然都c++11了,那就干脆就用新版的for语法了(说新,其实其他语言都已经这么干了)(vs2010不支持,2012没试过-xp装不上。。)
    <pre lang="cpp" line="1">
    for( auto &amp;x:container) {
    .....
    }
    </pre>

    或者你如果足够蛋疼可以试试Boost.Foreach

    Reply

  6. oldman

    oldman on #

    呃。。忘记给&amp;&amp;转义了。。
    看下这里吧 http://en.wikipedia.org/wiki/C%2B%2B11#Range-based_for-loop

    Reply

  7. yafei.zhang@langtaojin.com

    yafei.zhang@langtaojin.com on #

    Cut2Part这个函数不是C++的风格

    应该接受迭代器为参数的

    Reply

  8. yafei.zhang@langtaojin.com

    yafei.zhang@langtaojin.com on #

    typeof也只是GCC的扩展.
    你最后一个例子为什么不去看看BOOST_FOREACH是如何实现的.

    腾讯的不合格C++工程师真多

    Reply

    1. Dante

      Dante on #

      只针对你最后一句话。
      我实在不理解,你是否一定要用这种说话方式来找自信呢?

      Reply

      1. yafei.zhang@langtaojin.com

        yafei.zhang@langtaojin.com on #

        我呆过, 知道情况, 一把一把的不合格的

        Reply

        1. Dante

          Dante on #

          第一,我无法理解你所谓的合不合格的标准
          第二,我不知道你有没有判断别人是否合格的资格
          第三,就做人来说,我觉得你沟通的方式有些问题

          本博不想有这些无谓的争吵,有一争高下之心,大可绕道。

          Reply

          1. yafei.zhang@langtaojin.com

            yafei.zhang@langtaojin.com on #

            就事论事, 没必要吵.

            那你觉得你这篇文章里的哪一个piece写的比较精彩呢?

            Reply

          2. yafei.zhang@langtaojin.com

            yafei.zhang@langtaojin.com on #

            如果我的语言打击到你, 我表示道歉.

            我只是觉得有更优雅通用的方式, 没必要像你这样写的这么憋屈.

            Reply

            1. Dante

              Dante on #

              呵呵,本来我就不认同,怎么会受打击。

              同样,优雅通用与否,憋屈与否也是见仁见智。
              所以,你发表你的看法我没有意见,但是带有人身攻击的词语,这里不欢迎。

              Reply

              1. yafei.zhang@langtaojin.com

                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

                1. Zind

                  Zind on #

                  这位朋友,我实在看不下去了……
                  博主发文,是为了交流技术,分享心得……你在这里大放厥词,是为了砸场子么?
                  我姑且承认你是大牛,态度也不至于这么嚣张吧?如果认为这里太弱智,大可绕道。

                  Reply

                  1. Dante

                    Dante on #

                    感谢zind的支持~
                    yarfei,技术交流本身是件开心的事,何必这么浓的火药味。。

                    Reply

                    1. yafei.zhang@langtaojin.com

                      yafei.zhang@langtaojin.com on #

                      hi, 是你自己把火药味弄浓了, 我说的关于tx的事情都是我亲身体会. 我以前是在tx bj的. 不是专门针对你.

                      Reply

                      1. Dante

                        Dante on #

                        OK,那就休战吧。

                        Reply

                        1. yafei.zhang@langtaojin.com

                          yafei.zhang@langtaojin.com on #

                          取决于你的态度, 我一直都没有认为是战斗啊.

                          Reply

              2. yafei.zhang@langtaojin.com

                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() &gt; index + count)
                std::copy(src.begin()+index, src.end()+index+count, std::front_inserter(dst));
                return 0;
                }

                Reply

                1. Dante

                  Dante on #

                  yafei,没有人质疑你的能力,而是在说交流的态度,如果你只是想证明你更强,好吧,你赢了。

                  Reply

  9. Zind

    Zind on #

    我也来班门弄斧一个:
    // initialize elements of an array to 0
    template void init_array(T (&amp;array) [N])
    {
    for (size_t i = 0; i != N; ++i)
    {
    array[i] = 0;
    }

    return ;
    }

    Reply

    1. Zind

      Zind on #

      呃……我不知道怎么发帖啊,那一对尖括号似乎是被转义掉了……
      template 里面应该是有 typename T, size_t N

      Reply

      1. Dante

        Dante on #

        可以用pre标签哈,这个页面最上面有介绍:
        http://www.vimer.cn/index.php/%E7%95%99%E8%A8%80

        Reply

    2. Dante

      Dante on #

      模板推导,我也很喜欢用,哈哈

      Reply

      1. Zind

        Zind on #

        博主别跟 ls 的某某一般见识。
        它既然知道你是哪家公司的,应该是关注你博客有些时间了,肯定也读过你的不少博文。无论它从你的博客中是否学到了东西,或者学到了多少,这样对待一个知识产出者,都是无法接受的。

        Reply

        1. yafei.zhang@langtaojin.com

          yafei.zhang@langtaojin.com on #

          是, 我是学习VIM的, 我是VIM菜鸟.
          互相取长补短, 他的C++水平是不好, 远远差于他的VIM水平啊.

          Reply

  10. 编译点滴

    编译点滴 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&amp;ie=UTF8&amp;qid=1325165461&amp;sr=1-1

    Reply

  11. tecbbs

    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>
    我的将显示成了&lt;和&amp;gt:

    Reply

    1. Dante

      Dante on #

      很奇怪。。我有个朋友也说有这个问题,但是我自己用确实就没问题。。至今也不明白原因。。

      Reply

      1. tecbbs

        tecbbs on #

        我找到原因了,是我同时开了wp-syntaxhighlighter,关了就好了

        Reply

  12. hehe

    hehe on #

    其实作为一个学习者,我最喜欢出现像yafei.zhang这样的大牛来对我炮轰,要知道敢炮轰别人的,那都是有两把刷子的,如果你一旦虚心向炮轰我们的大牛请教,你的知识和见识会瞬间爬上一个高境界,这是求之不得的机会,所以我觉得博主应该赶紧对这些大牛表示感激涕零啊。而不是用凡夫俗子的观念来指责大牛的态度,大牛人家的自信和高傲是建立在扎实的学习之上的,不信你去挑挑大牛的代码的刺,人家一定对你感激,就算你骂大牛傻逼但是给出更牛逼的解答,大牛没准会和你做朋友。
    就这个大牛对你的代码点评来说,你的C++代码确实写得像一坨屎。人家大牛的方案的确更为纯粹,这其实是高人指点你。所以如果真的是虚怀若谷的话,何必介意大牛的语气呢。

    Reply

发表评论