现代 C++ 编程实战
吴咏炜
前 Intel 资深软件架构师
34196 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 51 讲
加餐 (1讲)
现代 C++ 编程实战
15
15
1.0x
00:00/00:00
登录|注册

13 | 编译期能做些什么?一个完整的计算世界

简易写法
remove_const 模板
trait 类模板
integral_constant 模板
<type_traits> 头文件
从1加到n的计算
通用的代表数值的类型模板
循环模板
条件语句模板
处理负数参数
编译输出验证
递归的阶乘函数
通用的 fmap 函数模板
编译期类型推导
模板元编程的基本概念
实际角度下的编译期计算
C++ 模板是图灵完全的
Wikipedia, “Fold (higher-order function)”
Wikipedia, “Map (higher-order function)”
cppreference.com, “标准库头文件 <type_traits>”
cppreference.com, “Standard library header <type_traits>”
Todd L. Veldhuizen, “C++ templates are Turing complete”
课后思考
模板的另外一种重要用途:编译期计算(模板元编程)
模板的基本用法及在泛型编程中的应用
参考资料
编译期能做些什么?一个完整的计算世界

该思维导图由 AI 生成,仅供参考

你好,我是吴咏炜。
上一讲我们简单介绍了模板的基本用法及其在泛型编程中的应用。这一讲我们来看一下模板的另外一种重要用途——编译期计算,也称作“模板元编程”。

编译期计算

首先,我们给出一个已经被证明的结论:C++ 模板是图灵完全的 [1]。这句话的意思是,使用 C++ 模板,你可以在编译期间模拟一个完整的图灵机,也就是说,可以完成任何的计算任务。
当然,这只是理论上的结论。从实际的角度,我们并不、也不可能在编译期完成所有的计算,更不用说编译期的编程是很容易让人看不懂的——因为这并不是语言设计的初衷。即便如此,我们也还是需要了解一下模板元编程的基本概念:它仍然有一些实用的场景,并且在实际的工程中你也可能会遇到这样的代码。虽然我们在开篇就说过不要炫技,但使用模板元编程写出的代码仍然是可理解的,尤其是如果你对递归不发怵的话。
好,闲话少叙,我们仍然拿代码说话:
template <int n>
struct factorial {
static const int value =
n * factorial<n - 1>::value;
};
template <>
struct factorial<0> {
static const int value = 1;
};
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了C++模板元编程的基本概念和应用。模板元编程允许在编译期间进行各种计算,实现了一个完整的图灵机,能够实现诸如阶乘计算、条件语句、循环等复杂计算。文章通过示例代码展示了如何使用模板元编程进行编译期计算,包括阶乘函数的实现、条件语句模板的定义、循环模板的使用以及整数常数模板的应用。此外,还介绍了如何使用模板元编程进行从1加到n的计算。读者可以了解模板元编程的强大威力,以及如何在C++中利用模板进行编译期计算。文章还指出了一些需要注意的细节,如使用`static_assert`来确保参数永远不会是负数,以及在使用`::`取一个成员类型时需要额外加上`typename`关键字。最后,文章提到了在现代C++中不使用模板元编程的方式也能达到同样的效果,为读者展示了模板元编程的发展方向。整体来说,本文通过具体的例子和技术细节,生动地展示了C++模板元编程的应用和潜力。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《现代 C++ 编程实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(29)

  • 最新
  • 精选
  • 禾桃
    脑壳儿疼的兄弟姐妹们,我这有个小偏方, 哈哈 While< Sum<2>::type >::type::value 实例化(instantiation)过程 --> While< SumLoop<0, 2> >::type::value --> WhileLoop<SumLoop<0, 2>::cond_value, SumLoop<0, 2>>::type::value --> WhileLoop<true, SumLoop<0, 2>>::type::value --> WhileLoop<SumLoop<0, 2>::cond_value, SumLoop<0, 2>::next_type>::type::value --> WhileLoop<true, SumLoop<2, 1>>::type::value --> WhileLoop<SumLoop<2, 1>::cond_value, SumLoop<2, 1>::next_type>::type::value --> WhileLoop<true, SumLoop<3, 0>>::type::value --> WhileLoop<SumLoop<3, 0>::cond_value, SumLoop<3, 0>::next_type>::type::value --> WhileLoop<false, SumLoop<3, -1>>::type::value --> SumLoop<3, -1>::res_type::value -->integral_constant<int, 3>::value -->3

    作者回复: 对,对于模板,就是要在脑子里或纸上、电脑上把它展开……☺️

    2019-12-25
    3
    17
  • 总统老唐
    记得吴老师之前预告过,这一节可能会比较难,确实被难住了。在第一个 If 模板这里就被卡住了,老师能给个简单的例子来说明这个 If 模板该如何使用么?

    作者回复: 下面的函数和模板是基本等价的: int foo(int n) { if (n == 2 || n == 3 || n == 5) { return 1; } else { return 2; } } template <int n> struct Foo { typedef typename If< (n == 2 || n == 3 || n == 5), integral_constant<int, 1>, integral_constant<int, 2>>::type type; }; 你可以输出 foo(3),也可以输出 Foo<3>::type::value。

    2019-12-25
    8
  • chang
    比如,如果我们对 const string& 应用 remove_const,就会得到 string&,即,remove_const::type 等价于 string&。 remove_const只能去顶层const。const string&应用remove_const后还是const string&,const string应用remove_const后是string。

    作者回复: 谢谢抓虫🙏。

    2021-06-03
    4
  • 莫言
    template < template <typename, typename> class OutContainer = vector, typename F, class R> 请问老师,这个OutConContainer前面的template<typename,typename>应该怎么理解

    作者回复: 模板的参数可以是类型(如 int),可以是值(如长度 8),也可以是其他(类或别名)模板。这个语法代表 OutContainer 是一个带两个类型模板参数的(类或别名)模板。(vector 有两个类型模板参数,第二个有默认值,一般不需要自己提供。)

    2021-12-27
    2
  • YouCompleteMe
    template <typename Body> struct whileLoop<true, Body> 部分似乎改成下面这样,更直观, 编译时计算更少呢 template <typename Body> struct whileLoop<true, Body> { typedef typename whileLoop< Body::next_type::cond_value, typename Body::next_type>::type type; };

    作者回复: 嗯,是的,你的写法能少展开一次。👍

    2020-01-16
    2
  • 李云龙
    分享一下我的代码:实现求最大公约数的辗转相除法 template <bool Cond, typename Body> struct WhileLoop; template <typename Body> struct WhileLoop<true, Body> { typedef typename WhileLoop<Body::Cond, typename Body::NextType>::type type; }; template <typename Body> struct WhileLoop<false, Body> { typedef typename Body::ResType type; }; template <typename Body> struct While { typedef typename WhileLoop<Body::Cond, Body>::type type; }; template <typename T, T val> struct integer { typedef T ValueType; static const T Value = val; typedef integer type; }; template <int lhs, int rhs> struct GCD { static const bool Cond = lhs % rhs != 0; static const int result = lhs; typedef integer<int, result> ResType; typedef GCD<rhs, lhs % rhs> NextType; }; int main() { cout << While<GCD<100, 56>>::type::Value << endl; return 0; }

    作者回复: 我测试了一下,似乎不行? 我就前面加了 <iostream> 的包含和 using。然后就报错了。

    2023-10-14归属地:北京
    3
    1
  • Geek_15f2c9
    老师,对万能引用使用完美转发是否好点,result.push_back(std::forward<decltype(f(item))>(f(item)))或result.emplace_back(std::forward<decltype(f(item))>(f(item)));;

    作者回复: 很好的问题。但是,实际必要性不高。 原因是,f(…) 极少会有合法的、返回右值引用的场景。唯一我能想到的可能性是返回值是根据输入的右值生成的情况。这样的话,得保证在输入是个右值容器时传递元素的右值给 f,所以真要考虑这种情况的话,代码比你写的还要再复杂不少……

    2021-04-28
    1
  • Gazelle
    我实践写了下remove_const,好像没有把const去掉。这里是不是有点问题呢? https://stackoverflow.com/questions/15887144/stdremove-const-with-const-references 我看这里说是如果同时有const和引用的话,还需要去掉引用? std::remove_const<std::remove_reference<const string&>::type>::type

    作者回复: 这里有个小细节:const T& 等同于 T const&,但和 T& const 不同。前者是一个指向常量的引用,后者是一个常引用。只有后者才被看作是一个“常量”。

    2020-11-29
    1
  • 鲁·本
    对While<Sum<10>::type>::type::value进行手动推导,最终是能推导出实际语句是 integral_constant<int,10+9+...1>::value的,但让我独立写出 完整的代码是万万不能的😄

    作者回复: 哈哈,我写的时候头也很大。只是为了说明能写出来,而不是真想/需要这么写。

    2020-10-11
    1
  • 吃鱼
    “如果要得到布尔值的话,当然使用 `is_trivially_destructible::value` 就可以,但此处不需要。需要的是,使用 `()` 调用该类型的构造函数,让编译器根据数值类型来选择合适的重载。这样,在优化编译的情况下,编译器可以把不需要的析构操作彻底全部删除。” 老师,这里没太懂,使用 `()` 调用该类型的构造,这里的调用是在哪里调用,为什么 destroy 要调用构造函数

    作者回复: 指的就是这句: _destroy(ptr, is_trivially_destructible<T>()) 这儿构造了一个 true_type 或 false_type 的对象,然后编译器会根据第二个参数的类型,决定调用 _destroy 的哪个重载。

    2020-06-02
    3
    1
收起评论
显示
设置
留言
29
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部