记初入c++模板元

4 篇文章 0 订阅
1 篇文章 0 订阅

 

一:问题

一个问题:打印250(包括250)以内的所有素数;

第一种方法:自己找出所有的素数,并放入一个数组中,可能的一种代码如下:

#include <iostream>

int main()
{
    int primes[] = { 2, 3, 5, 7, 9, 11, 13 .......... };//需要自己找,自己算,猝死.......

    //打印
    for(int i = 0; i < sizeof(primes); ++i)
        std::cout << "第" + << i + 1 << "个素数是: " << primes[i] << std::endl;

    return 0;
}

第二种方法:让程序帮我们找,我们可以写一个判断是不是素数的函数,然后再写一个循环,一种可能的代码如下

#include <iostream>

bool isPrime(int i)
{
    /*
     * 具体实现,只需判断sqrt(i)以内有没有是i的因子,具体实现就不写了
     */
    ...
}

#define N 250

int main()
{
    //记录总共多少个
    int count = 0;

    for(int i = 2; i <= N; ++i)
    {
        if(isPrime(i))
        {
            ++count;
            //打印
            std::cout << "第" + << count << "个素数是: " << i << std::endl;
        }
    }

    return 0;
}

现在我们看一下这两种方法,第一种应该没有人愿意那样写吧,所以直接看第二种;

第二种方法中,程序运行之后,会帮我们一个一个的判断哪些是素数,如果当前这个数是素数,那就打印出来;

第二种方法是没有任何问题的,但250以内的素数有几个,是哪些,不管如何这些一定是确定下来的,只是我们懒得计算,将这个任务交给了程序,让程序帮我们计算,这样势必会让程序做一些不必要的计算,我们希望一个程序只计算它必须要计算的;

那么有没有一个折中的方法,我们可以多敲一些代码,但同时又不需要我们自己找、自己算;答案肯定是有,那就是模板元

二:模板元

模板元说到底就是让编译器帮我们算好,然后程序就可以直接使用(本来我们可以自己算出来的,就像第一种方法一样)

首先来一个最简单最常见的:模板元计算n!(n的阶乘)

一种可能的代码如下:

#include <iostream>

template <int N>
struct Fac
{
    enum { value = N * Fac<N-1>::value };
};

template <>
struct Fac<1>
{
    enum { value = 1 };
};


int main()
{
    std::cout << "10的阶乘 : " << Fac<10>::value; // 10的阶乘 : 3628800 

    return 0;
}

在上面的程序中,编译器会帮我们计算出10!,当然如果我们要自己算的话,你需要准备一根笔,一本草稿本,然后按照阶乘的定义一步一步算;

然后回到正文,怎么找250以内的所有素数呢?

废话不多说,直接上源码;

#include <iostream>
#include <vector>

//模板元选择结构
template <bool isPrime, typename Then, typename Else>
struct If
{
    typedef Then Ret;
};

template <typename Then, typename Else>
struct If<false, Then, Else>
{
    typedef Else Ret;
};

//
template <bool bValue>
struct Bool
{
    const static bool value = bValue;
};

//辅助IsPrime计算
template <int M, int N>
struct Prime
{
    const static bool value = If<!!(M % N), Prime<M, N - 1>, Bool<false> >::Ret::value;
};

//辅助IsPrime计算, 一直算到2终止计算
template <int M>
struct Prime<M, 2>
{
    const static bool  value = If<!!(M % 2), Bool<true>, Bool<false> >::Ret::value;
};

//判断数N是否为一个素数,如果N是素数则value = true,否则为false
template <int N>
struct IsPrime
{
    const static bool value = Prime<N, N-1>::value; //Prime会自动帮我们算出N是否是一个素数
};

//2是素数,但2无法通过Prime来计算判断,所以使用特例化
template <>
struct IsPrime<2>
{
    const static bool value = Bool<true>::value;
};

//寻找 <= N 的所有素数,并存放进m_vec中
template <int N>
struct VecPrime
{
    VecPrime () { init(m_vec); }

    static inline void init(std::vector<int> &vec)
    {
        VecPrime<N - 1>::init(vec);  //在放入N之前先判断 N - 1 是不是素数,等于说是用递归实现了循环
        if(IsPrime<N>::value)  //如果N是素数,则放入vec中
            vec.push_back(N);
    }

    std::vector<int> m_vec;
};

//数字1比较特殊,特别对待,使用模板特例化
template <>
struct VecPrime<1>
{
    static inline void init(std::vector<int> &vec) {  }
    std::vector<int> m_vec;
};

#define N 250

int main()
{
    VecPrime<N> vecPrime; //(不考虑vector容器和数组的细微区别)此处等价于第一种方法中的 int primes[] = { 2, 3, 5, 7, 9, 11, 13 .......... };
    for(int i = 0; i < vecPrime.m_vec.size(); ++i)
        std::cout << "第" << i + 1 << "个素数是: " << vecPrime.m_vec[i] << std::endl;

    return 0;
}

至此,就算是成功使用模板元找到250(包括250)以内的所有素数;

总结:

巧妙的使用模板元,可以将很多计算转移到编译期,从而提升程序的执行速度,但缺点也很明显,需要多码很多代码,而且代码不怎么好阅读,一旦编译报错,很容易让人懵逼,不知道从哪找错

当然,这仅仅是入门,不好做过多的评价;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值