首页
Preview

元编程:C++步骤介绍

更新: 我在Reddit上被告知这是C++编程和编译器优化的一个旧观点。如果你熟悉模板元编程并想了解最新情况,请前往Reddit的评论帖子

一个模板及其阶乘的用法。

什么是模板元编程?

“元编程指的是程序具有自我知识或可以操作自身的各种方式。”维基百科如此写道。当我作为一名新手研究生第一次读到这句话时,我的想象被AI程序能够编写其他代码片段并接管世界的可能性所震撼。虽然这是好莱坞版本,但这是一种在工业界使用C++模板进行编译时优化的现实。

我在研究一项涉及优化的项目时遇到了这个概念。虽然它不是远离CS101课程基础的概念,但它并不是很广为人知,因此写了这篇博客来介绍它。

让我们首先看看什么是模板:模板是泛型编程的基础,它涉及以与任何特定变量类型无关的方式编写代码。

例如,看一下以下代码:

#include <iostream>using namespace std;
// One function works for all data types.  template <typename T>
T tMax(T x, T y) 
{ return (x > y)? x: y; }
int main()
{cout << tMax<int>(3, 7) << endl; // Call myMax for type int
cout << tMax<double>(3.0, 7.0) << endl; // call myMax for type d
cout << tMax<char>(’g’, 'e’) << endl; // call myMax for type charreturn 0;
}

模板tMax提供了一个通用函数,可被所有数据类型使用。

模板如何工作?

模板通过汇编器编译为实际类型

模板本身在程序编译后不存在,即在汇编代码中不存在。

如上面我们看到的tMax模板示例中,模板tMax会在编译时转换为针对代码中调用的每种类型的不同函数。参考:汇编代码(第38行定义了函数_int tMax<int>(int,int)_,它是int类型的tMax)

你可能希望转到Tutorials Point(C++ Templates)花费一些时间学习模板。Java提供的等效构造是Generics

使用模板进行优化

由于模板在编译时“展开”为函数,并且编译器在编译时执行变量不涉及的计算,因此一些计算可以在编译时完成并在运行时避免。

计算可以在编译时完成并在运行时避免

假设你正在编写一段代码,并且你想要在代码中使用值为15!(15的阶乘)。递归的方法是使用以下代码:

long factorial(int n)
{
  if (n == 0)
    return 1;
  else
    return(n * factorial(n-1));
}int main()
{
  cout << factorial(15) << endl;
  return 0;
}

这将编译为一个函数和对该函数的调用,其中参数n=15将在运行时执行。参考:汇编代码(你可以在第17行看到阶乘函数和一个_call factorial(int)_)

现在让我们将其转换为使用模板的程序。

template <long N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};template <>
struct Factorial<0> 
{
    enum { value = 1 };
};int main()
{
    cout << Factorial<15>::value << endl;
    return 0;
}

在编译时,编译器将模板Factorial展开为参数N=15,并遇到参数N=14的模板,依此类推,直到N=0。由于这些计算中没有遇到任何变量,因此它们在编译时解决,Factorial<15>最终在编译时解决为15!即1307674368000,从而避免了任何运行时计算。你可以在组装代码中看到直接使用值1307674368000而不是调用函数。参考:汇编代码(没有函数定义,因为汇编器已经计算出了15!的值,并在第4行中使用)

使用时间分析(和太多迭代)执行两个实现可以显示优化的影响。模板化代码运行时间约为0.03ms,而递归版本运行时间长至少30倍,如预期的那样,在运行时计算阶乘并进入递归。

其他示例:模板和专用函数。

更深入(更复杂,更有价值)的示例来自Template Metaprograms(Todd Veldhuizen)。使用模板进行冒泡排序似乎不太直观,因为输入不是单个数字,但是想法是创建一个模板,该模板展开为适用于特定元素数量的专用函数进行冒泡排序。我强烈建议阅读该示例并解决详细问题。

这在哪里使用?

我首先想到的是为什么我们需要执行像调用模板的函数这样的函数,如果没有涉及变量。这不等同于使用值本身编写代码(例如,在Factorial&lt;15&gt;的位置上放置1307674368000)。对此的反驳是需要抽象函数,而不是在代码中随意散布值。

因此,Boost库利用模板提供了复杂函数的库,例如阶乘,正弦,余弦等,以确保在可以在编译时完成计算的任何地方不在运行时计算值。总之,模板是一种很好的技巧,可以确保编译时计算,并在时间关键项目中节省一些运行时间(高频交易,可能是航空和航天)。

请查看SO以获取有关模板元编程的社区讨论。如果你在你的代码中使用过,请在下面发表评论并分享你的经验。

译自:https://levelup.gitconnected.com/template-metaprogramming-a-c-walkthrough-a7c6db0b4148

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
thorepet
没有你想不到,只有你做不到……

评论(0)

添加评论