C++模板元编程是一种函数式编程形式吗?

14
C++ 模板元编程是一种函数式编程形式吗?如果是,那么像非尾递归的堆栈溢出等问题对于 C++ 模板元编程是否有关联?在 this question 的阶乘模板示例中,我猜它是标准的函数式编程。或者这种相似性只是表面上的?
#include <iostream>
using namespace std;

template< int n >
struct factorial { enum { ret = factorial< n - 1 >::ret * n }; };

template<>
struct factorial< 0 > { enum { ret = 1 }; };

int main() {
    cout << "7! = " << factorial< 7 >::ret << endl; // 5040
    return 0;
}

7
C++模板实际上是一门非常纯净的函数式编程语言(没有副作用!),其特殊之处在于完全在编译时进行评估,而不像大多数函数式语言在运行时进行。而且语法并不太好。因此,使用与一种语言相同的技术和算法也适用于另一种语言是有意义的。事实上,存在将Haskell的子集“解糖”为C++模板的项目。我对性能特征/“操作语义”不太了解。 - glaebhoerl
2
也许你应该看一下boost::phoenix - Jesse Good
2
这绝对是一个真正的问题。只不过它有点深奥。 - Marcin
@Marcin:‘不是一个真正的问题’的描述为“这个问题含糊不清,模糊不清,不完整,过于宽泛或者是修辞性的,并且不能以当前的形式合理地回答。”--我认为这个描述完全适用。 - ildjarn
1
@ildjarn 这个问题怎么能算是宽泛的呢?它非常具体明确。 - Marcin
@Marcin:现在是这样,关闭时不是这样。 - ildjarn
3个回答

9
这是一篇关于C++模板元编程是否属于函数式编程的文章。

是的!模板展开没有副作用,因此它是纯函数式的。

如果是这样,像非尾递归的栈溢出这样的陷阱对于C ++模板元编程是否相关?

完全正确。 阶乘并不是一个很好的演示,因为结果会在堆栈之前溢出,但长递归肯定会导致编译器错误。 有趣的是,编译器倾向于以这样的方式实现模板,使您获得自动记忆化。例如,一个粗略编写的斐波那契数列的实现通常会在O(n)时间内编译,而不是O(2 ^ n)。


7

我认为最好的答案是这两个概念完全不同。然而,这并没有真正帮助到你,所以下面是我能想到的一些关键点:

  • C++模板和函数式语言(如ML中的参数多态)都是泛型编程的例子,因此将它们放在一个问题中一起提出是有意义的。在学术界,甚至有泛型编程研讨会,通常涉及C++模板和ML风格的函数式编程。

  • 然而,模板元编程为您提供了一种编写代码的方式,在编译C++代码时“评估”该代码,因此您只能将其用于非常有限的任务。另一方面,函数式程序通常在运行时运行,并且您可以定义复杂的数据结构,构建抽象等等(使用模板元编程也可以做一些事情,但看起来会很丑陋)。

  • 为什么阶乘示例类似于函数式编程中的阶乘?当您使用模板元编程时,您无法定义“可变变量”(因为您只是定义新类型或模板),因此模板元编程可能感觉有点像函数式编程风格。

  • 使用模板元编程编写的代码在编译时进行评估。这意味着它不能依赖用户输入!它要么编译,要么不编译(编译器可能对递归深度有一些限制,并在某个时候放弃)。另一方面,函数式程序可以接受一些输入,然后进行评估(这意味着它们可以使用所有可用的堆栈或内存,然后失败)。

对于函数式编程者来说,我知道一些函数式语言(比如Agda)可以在编译时计算东西,但我认为保持简单更好!

19
它们并非完全不同的东西。更接近事实的说法是它们是相同的东西:C++模板元编程是函数式编程。(当然,反过来则不成立。) - glaebhoerl
4
关键点与您的陈述相矛盾:C++模板元编程和函数式编程并不相同,但非常接近。事实上,在C++中,您可以在编译时解析(Haskell的子集)函数式程序,并进行转换甚至执行它。例如,可以看看这里的一个库http://abel.web.elte.hu/mpllibs/metaparse/index.html,它可以实现这一点。 - Zólyomi István
2
你们两个都提出了一些好观点,但我仍然认为它们在高层次上是完全不同的东西。在低层次上,它们共享一些技术方面(例如模板元编程使用函数式风格的子集),但如果你想考虑大局,这并不是真正有用的信息。 - Tomas Petricek
2
从根本上讲,函数式编程是完全由无副作用的评估组成的编程,这完美地描述了模板元编程。寻找像用户输入之类的功能是无关紧要的;一些函数式语言(例如λ演算)不接受用户输入。 - Sneftel

0

模板元编程在理论上是一种纯函数式语言,即函数仅依赖于它们的参数,而不考虑任何全局或本地状态。然而,通过友元注入,我们可以捕获和检索元编程状态。因此,函数可以根据全局/本地元编程状态返回不同的结果。


检索元编程状态从未被设计,根据ISO委员会的观点,“这是神秘的,应该被视为不合规”,如CWG 2118所述。 - dfrib

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接