跟我学c++高级篇——c++模板元编程之十二c++11对模板元编程的支持和扩展

一、模板元编程在c++中的发展

模板元编程从本质上看和函数编程有些类似。其实偏底层的语言就是有这个好处,怎么抽象怎么封包一下,就会和高级的语言或者其它应用方式感觉相同。c++的元编程,对每一个c++开发人员来说,都是一个很深的技术,会用和会写到会设计,这需要一个很长的时间才能达到。更不要提到最后融会贯通,自由收发。
模板元编程,其实在底层库或者框架中应用更多,这也是为什么很多c++开发人员为什么写了很多代码,工作了很长时间也没有没接触过的原因。毕竟,咱们国内的整体软件形式大家也都明白,拿来主义还是盛行。这里不谈此风好与坏,合适的就是最好的。
早期的元编程在知乎上有人挖过坟,是一个不能编译成功的例子,后来慢慢被一些牛人完善出来。它是一种不经意的过程,是一种模板编程的外溢。这种提法其实就是说明,它的编程模式和普通的模板编程模式是有区别的,这种区别就是不让一般开发者容易明白。包括在后来看到的SFINAE技术。当真,对大多数人来说,这不是技法,更像灾难。飞机很好用,但不会开。
c++的标准委员会当然不会坐视不理,毕竟,牛人自己写那个也麻烦啊,就像开飞机,不小心,飞机就要掉来来的感觉。所以基础设施不断的随着标准的升高而完善,从一些新的模板类和函数封装起来,减少复杂度增加易接受程度到干脆另起炉灶引入更新的概念和更好的基础设施。Concepts就是一个典型的例子。

二、c++11及以后续版本中的模板元编程

不可否认,相对于其它语言,c++语言本身的应用就是复杂的(灵活)。而模板编程则更上一层,正如有的人在网上所言,他们公司禁止使用模板。模板编程的难点对于初学者是非常不友好的,一个重要的体现点在于,模板的错误,即使非常小,也会有一大片的错误,可能大多数人一下子就晕了。那么可想而之,高手们眼中模板元编程是一门新语言的建议,能不让新手们望而却步么?更何况,它的应用范围又不大(虽然很底层,是一个重要的基础设施)。
这样看来,这不是c++标准委员会的大牛们想看的。毕竟,用得多,用得广,才会使c++更容易不断发展下去。那么在新的c++11及以上标准里就提供了大量的简化的元编程方法,大量的元函数被封装起来,直接被调用,更是在c++20推出了Concepts进一步简化相关的元编程的应用。
下面看几个提供的常用的元函数:

std::is_integral:整形检查
std::is_same:二者类型是否一致
std::integral_constant:包装特定数据类型,在bool时可用于元编程的分支控制
std::enable_if:根据第一个形参的bool值得确定第二个形参的公开成员typedef type是否使用
std::integer_sequence:这个在前面用过,元编程中产生整数序列(数组)

更多的请参考:https://en.cppreference.com/w/cpp/meta#Type_traits
元编程确实难,但只要坚持用,坚持思考,达到在实际中应用还是没有什么问题的。

三、应用和相关学习资料

讲了很多元编程的优点,但在实际应用中其实还是有不少困难的。最典型的就是两个:
1、开发,首先是一个编程习惯和开发思想的转换,包括设计思想,代码调试手段等等,都需要转变。另外前面提到过,元编程主要在库和框架中使用,而这点在国内恰恰又是短板中的短板(国内更强调用功能),所以互相学习的可能性以及获取帮助的可能性都很小。这就意味着出现问题,更多的依赖自己去查找资料。

2、应用,一般来说,开发一个动态库甚至一个框架,只要给个头文件说明基本就搞定了,而相关的算法和需要控制的代码都被安全的放在库里。而元编程采用模板技术,代码的实现目前基本只能在头文件中,也就是说,交出头文件的同时,源码就全暴露了。而模板的特性是不使用不编译,所以如果当使用一个头文件时或者多处使用时,就会发现编译时间增加了(当然,小规模的应用就忽略了)。同时,还有一个更重要的问题,一般应用方的很少有对技术掌握特别深的,这就意味着,给对方元编程的代码文件,如果没有详细的说明文档,对方可能会很排斥,毕竟模板本身就很复杂了,再加个元编程。

这里给大家推荐几本书,正如在前面介绍,学好c++模板元编程,其实主要有三本书可以做为打基础(有的是有多个版本也算一个),一个是《C++ Templates The Complete Guide》,这个第一版中有侯捷老师版本的,有陈伟柱老师版本的,最新又出来了第二版,可惜没有比较正式的中文版。另外一个是《Modern c++Design》中文版叫《c++设计新思维》;还有一个就是《c++模板元编程》(c++ Template Metaprogramming),这些书相对来说都比较老了。有一本国内牛人写的书《c++模板元编程实战》值得学学。
其它还有很多书籍,大家在学习完成上面的书后可以参考。网上也有很多牛人的相关的博客或者公众号,大家取其精华即可。
学习是一个漫长的过程,不要妄想一蹴而就。

四、例程

还以前面的函数判断为例子,就可以看出的版本前进引起的简化:
1、老版本

template <typename T, void (T::*)(const typename T::value_type&)>
struct IsHave;

template <typename T, void (T::*)(typename T::value_type)>
struct IsHas;

template <typename T>
bool ishas(...)
{
    return false;
}
template <typename T>
bool ishas(IsHave<T, &T::push_front>*)
{
    return true;
}
template <typename T>
bool ishas(IsHas<T, &T::push_front>*)
{
    return true;
}
int main()
{
    std::cout << ishas<std::list<int> >(NULL) << std::endl;
    std::cout << ishas<std::vector<int> >(NULL) << std::endl;
    return 0;
}

看上去还是有点复杂,但是它和前面的must判断原理是一样的,通过替换是否成功来决定结果。

2、c++11版本
c++11版本就简单不少,看下面的例子:

template <typename>
using void_t = void;

template <typename T, typename V = void>
struct IsHave :std::false_type {};

template <typename T>
struct IsHave<T, void_t<decltype(std::declval<T>().push_front(std::declval<typename T::value_type>()))>> :std::true_type {};

int main()
{
    std::cout << IsHave<std::list<int>>::value << std::endl;
    std::cout << IsHave<std::vector<int>>::value << std::endl;
    return 0;
}

这个相对上面就更简单更容易理解,而且更灵活。

3、c++20更新版本
在concept推出后,这个版本更简化了,前面有太多的例子了,这里就不再重复,有兴趣可以根据前面的再结合此例子写一下。

五、总结

模板元编程写到这里,暂时先告一个段落。基本的元编程的技术都覆盖到了,更深或者更抽象的设计这个需要不断的迭代理论和实践,不断的紧跟着c++标准前进。可能以前复杂的方式在高版本的c++标准里就是简单的一两行代码,但是这两行代码恰恰是前面复杂实现过程中不断总结抽象出来的经验。
不断自省,不断前进,不断挑战自我,与诸君共勉。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值