我有一些模板化的代码,编译器可以为大多数数据类型而不是其他数据类型进行尾调用优化。该代码实现了pow()
template<typename T, typename U>
void powRecurse(T& x, U& y, T& acc)
{
if(y == 0) {
acc = Identity<T>;
return;
}
if(y == 1) {
acc = acc * x;
return;
}
if(y % 2 == 1) {
acc = acc * x;
y = y - 1;
}
x = x*x;
y = y/2;
powRecurse<T, U>(x, y, acc);
}
template<typename T, typename U>
T tailPow(T x, U y)
{
T rv = Identity<T>;
powRecurse<T, U>(x, y, rv);
return rv;
}
参数T的类型似乎对尾调用优化没有影响,我试过的任何类型都可以使用参数U的正确类型进行尾部调用优化。如果参数U是uint64_t,编译器可以尾调用优化。如果它是boost :: multiprecision :: cpp_int那么编译器不会尾调用optimize。
我还尝试在一个类中包装一个uint64_t,在一个int类型上包装一个模板包装器,它们都尾调用optimize。
有什么理由不应该尾调用优化?显然我可以循环这个,但我真的只是想在这里理解语言或编译器问题。
答案 0 :(得分:1)
懒惰评估意味着所有&#34;递归&#34;函数调用实际上是不同的函数模板实例化。
参见例如这里有类似的讨论:
因此,您可以通过选择退出惰性评估模板表达式(boost::multiprecision::et_off
,如链接中所述)来获得所有tail-coll实现细节,但请务必检查是否已减少代码大小和感知的TCO优化实际会提高性能。
实际上,某些算法可以从表达式模板中受益,这些模板可以跳过常见的子表达式,重新排序无损操作等。