模板元编程是否比同等的C代码更快?

n00*_*ki3 11 c c++ language-agnostic templates metaprogramming

模板元编程是否比同等的C代码更快?(我说的是运行时性能):)

jal*_*alf 27

首先,免责声明:我认为您所询问的不仅仅是模板元编程,还包括通用编程.这两个概念密切相关,并没有确切定义每个概念.但简而言之,模板元编程实质上是使用模板编写程序,这些模板在编译时进行评估.(这使得它在运行时完全免费.没有任何反应.值(或更常见的类型)已经由编译器计算,并且可用作常量(const变量或枚举)或typedef嵌套在一个类中(如果你用它来"计算"一个类型).

通用编程使用模板,并在必要时使用模板元编程,以创建通用代码,其工作方式相同(并且没有性能损失),具有全部和任何类型.我将在下面使用两者的示例.

模板元编程的一个常见用途是使类型能够用于泛型编程,即使它们不是为它设计的.

由于模板元编程技术上完全是在编译时进行的,因此您的问题与通用编程有点相关,通用编程仍然在运行时进行,但效率很高,因为它可以专门用于编译时使用的精确类型.

无论如何...


取决于您如何定义"等效C代码".

关于模板元编程(或一般的通用编程)的技巧是它允许将大量计算移动到编译时,并且它使得灵活的参数化代码能够像硬编码值一样高效.

这里显示的代码例如在编译时计算斐波纳契序列中的数字.

C++代码' unsigned long fib11 = fibonacci<11uL>::value'依赖于该链接中定义的模板元程序,并且与C代码一样高效unsigned long fib11 = 89uL.模板在编译时进行评估,产生可分配给变量的常量.所以在运行时,代码实际上与简单赋值相同.

因此,如果这是"等效C代码",性能是相同的.如果等效的C代码是"一个可以计算任意斐波纳契数的程序,用于查找序列中的第11个数字",则C版本会慢得多,因为它必须作为函数实现,它计算值在运行时.但这是"等效C代码",因为它是一个具有相同灵活性的C程序(它不仅仅是一个硬编码常量,而是一个可以返回fibonacci序列中任何数字的实际函数).

当然,这通常不常用.但它几乎是模板元编程的典型例子.

通用编程的一个更现实的例子是排序.

在C中,您有qsort标准库函数,它带有一个数组和一个比较器函数指针.无法内联对此函数指针的调用(除非在普通情况下),因为在编译时,不知道将调用哪个函数.

当然,替代方案是为您的特定数据类型设计的手写排序功能.

在C++中,等效的是函数模板std::sort.它也需要一个比较器,但它不是一个函数指针,它是一个函数对象,如下所示:

struct MyComp {
  bool operator()(const MyType& lhs, const MyType& rhs) {
     // return true if lhs < rhs, however this operation is defined for MyType objects
  }
};
Run Code Online (Sandbox Code Playgroud)

这可以内联.该std::sort函数传递一个模板参数,因此它知道比较器的确切类型,因此它知道比较器函数不仅仅是一个未知函数指针,而且MyComp::operator().

最终的结果是,C++函数std::sort恰好在同一排序算法的C本手工编码实现高效.

再说一遍,如果那是"等效的C代码",那么性能是相同的.但是,如果"等效C代码"是"可以应用于任何类型的通用排序函数,并允许用户定义的比较器",那么C++中的通用编程版本效率要高得多.

这真的是诀窍.通用编程和模板元编程不是"比C更快".它们是实现通用,可重用代码的方法,它与手动编码和硬编码C一样快

这是一种充分利用这两个世界的方法.硬编码算法的性能,以及一般参数化算法的灵活性和可重用性.


Mic*_*urr 11

模板元编程(TMP)在编译时是"运行"的,所以在将它与普通的C/C++代码进行比较时,并不是真的比较苹果和苹果.

但是,如果您通过TMP评估了某些内容,那么根本就没有运行时成本.