Bjarne Stroustrup的C++11 FAQ about templates包含以下词语:
这是在编译时完成的标准函数式编程。
这是否意味着his example with printf
在编译后应该是递归的节点?我简化了一些示例,所有具有禁用优化的编译器都会生成递归代码。例如,这里是the output from g++ -O2
,它不是递归的,但是无论如何,clang都会保持递归。
我错过了什么?
P.S。我的错误。在这个示例中,具有优化选项的clang编译代码与所有其他代码一样 - 以简单的方式(无递归)。但是没有优化 - 所有仍然使用递归进行编译。
答案 0 :(得分: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>
那么
Length<int, int, int, int>
实例化Length<int, int, int>
,实例化Length<int, int>
,实例化Length<int>
,实例化Length<>
这个过程是Bjarne所指的模板的纯函数式递归扩展。这是扩展模板以生成代码的过程,该代码是在编译时递归完成的,而不是在编译器中展开的实际生成的代码。只要不改变代码的基本含义,C ++编译器就可以自由地优化代码,但它认为合适。如果你有一个使用这种编译时递归方式的递归函数,编译器可能优化它,但不能保证它会。 C ++标准对允许或不允许的哪种优化没有任何限制,只是描述了所需的行为,因此没有相关的规则。
希望这有帮助!
答案 1 :(得分:1)
仅仅因为他说“这是在编译时完成的标准函数式编程”并不意味着生成的结果代码在运行时完全是非递归的。他的陈述根本没有提到运行时间。
没有提到编译器应该在运行时生成什么。消除可变参数模板函数递归的唯一方法是对所有递归调用进行内联,尾调用优化和/或编译器以某种方式将代码重新排列为循环。所以这完全取决于编译器。