3

Bjarne Stroustrup关于模板的 C++11 常见问题解答包含以下词语:

这是在编译时完成的相当标准的函数式编程。

这是否意味着他的示例printf在编译后应该是节点递归的?我稍微简化了示例,所有禁用优化的编译器都会生成递归代码。例如,这是的输出g++ -O2,它不是递归的,但无论如何 clang 都会保持它的递归。

我错过了什么?

PS有我的错误。在此示例中,带有优化选项的 clang 像所有其他代码一样编译代码 - 以一种简单的方式(无递归)。但如果没有优化 - 所有仍然使用递归编译。

4

2 回答 2

3

Bjarne 关于编译时递归的评论是指评估模板的方式,而不是生成代码的工作方式。例如,考虑以下模板:

template <typename... Args> struct Length;
template <> struct Length<> {
    static const size_t value = 0;
};
template <typename First, typename... Rest> struct Length {
    static const size_t value = 1 + Length<Rest>::value;
};

在这里,如果我们实例化Length<int, int, int, int>then

  • Length<int, int, int, int>实例化
  • Length<int, int, int>, 它实例化
  • Length<int, int>, 它实例化
  • Length<int>, 它实例化
  • Length<>

这个过程是 Bjarne 所指的模板的纯函数递归扩展。这是扩展模板以生成递归并在编译时完成的代码的过程,而不是在编译器中展开的实际生成的代码。C++ 编译器可以自由地优化代码,但它认为合适,只要它不改变代码的基本含义。如果你有一个使用这种编译时递归风格的递归函数,编译器可能会优化它,但不能保证它会。C++ 标准对允许或不允许的优化类型没有任何限制,只是描述了所需的行为,因此没有关于此的规则。

希望这可以帮助!

于 2013-10-04T19:50:06.970 回答
1

仅仅因为他说“这是在编译时完成的相当标准的函数式编程”并不意味着生成的结果代码在运行时是完全非递归的。他的声明根本没有提到运行时。

没有提到编译器应该在运行时生成什么来执行。消除可变参数模板函数的递归性的唯一方法是内联所有递归调用,优化尾调用和/或让编译器以某种方式将代码重新排列成一个循环。所以这完全取决于编译器。

于 2013-10-04T19:49:25.053 回答