STL之浅谈std::conditional

问题背景:为什么有三元运算符了,std还要实现诸多类似std::conditional的模板呢?

结论:完全实例化(展开)问题,避免模板编程带来的空间开销

初步探索

  • 首先来看下测试用例的代码
#include <iostream>
//#include <type_traits>//struct conditional
using namespace std;
/***********************
      v=a*(a-1)*(a-2)*...*1;
***********************/
//part one
template<int _Cond, typename _Iftrue, typename _Iffalse>
struct IfElse
{};

template<typename _Iftrue, typename _Iffalse>
struct IfElse<false, _Iftrue, _Iffalse>
{
    typedef _Iffalse type;
};

template<typename _Iftrue, typename _Iffalse>
struct IfElse<true, _Iftrue, _Iffalse>
{
    typedef _Iftrue type;
};

template <int _Val>
struct Recursion{
    enum { val = Recursion<_Val-1>::val * _Val};
};
template<>
struct Recursion<1>{
    enum {val = 1};
};

template <int Va,int Vb>
struct TestIfElse{
    typedef typename IfElse< (Va > Vb), Recursion<3>, Recursion<4>>::type ResultVal;
};


void RecTest()
{
    int a,b;
    cin >> a;
    cin >> b;
    int v = a > b ? Recursion<3>::val : Recursion<4>::val;
    v = TestIfElse<1,2>::ResultVal::val;
    v = 1 > 2 ? Recursion<3>::val : Recursion<4>::val;
}

//part two
class Int{
public:
    Int()=delete;
    ~Int()=default;
    Int(int _v):val(_v){ cout << "constructor: " << val <<endl; };
    const int val;
};

template<int _Val>
class IntRecursion{
public:
    const int Val=Int(_Val).val * IntRecursion<_Val-1>().Val ;
};
template<>
class IntRecursion<1>{
public:
    const int Val=Int(1).val ;
};

void IntRecTest(int a,int b)
{
    int v = a > b ? IntRecursion<4>().Val : IntRecursion<3>().Val;
    v = 1 > 2 ? IntRecursion<4>().Val : IntRecursion<3>().Val;
    cout << v <<endl;
}

int main()
{
    RecTest();
    IntRecTest(1,2);
    return 0;
}

  • 在part one中的用例最后是由RecTest函数来测试的,在测试之前可以先猜猜这个函数中的最后三行都有啥区别,这个也是原因所在

来看看汇编代码,在图中的14~25行对应着函数的最后三行代码,可以看出,使用了TestIfElse的和三元运算符已经确定的情况下一样(看TestIfelse里的typedef,实现情形和14行的情形是一样的(a和b都还不确定),只计算出来Recursion<4>的值;而14行那个语句却计算了参数值为3和4的值(18行和19行),这个可能与三元运算符的机制相关。这就可以基本猜到,使用模板进行比较,可以少实例化(准确来说,是实例化对象,而代码层层面都是一样的,意思就是说,模板解析后22行和14行都计算了参数3和4的值,但是就是有没有实例化的问题,/*因为模板一有变化就是一种不同的类型*/);

  • 接着再来看part two的汇编代码

在part two中,和在part one中实现的东西基本是一样的,这次的参数,我封装了一个Int类来看它构造了几个对象

可以看到第19和31行,它和part one中,ab参数都不确定时候一样,调用了两个函数,而当ab确定时候,它却只调用了参数为3的(45行),这就验证了上面的结论。

而在打印中,却这打印了两次参数为3的,没有打印参数为4的(即19行的值嘞?),我想,这个是因为这个是因为与class Int相关,因为在IntRecursion模板中使用的是一个类对象,它是在运行时,在栈分配的空间,虽然它在汇编代码里面是实例了,但是在运行的时候没有实例化改对象,因此没有打印。

 

其他杂言

  • 模板的本质还是对象类型,它是在编译时就已经实例化好了(这里的实例化和类的实例化有些不一样,可以理解成类似宏展开),而类的实例化是要在运行时
  • 我记得在《C++ template》中有提到过,模板的递归有限制(好像是不能超过14还是17层),测试了,是可以的,可能是那本书是基于98版的
  • 模板编程是以空间换运行效率
  • 很久没碰模板了,有些生疏,有问题欢迎留言

 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值