在铛下面的函数产生目标码为一个尾递归函数:为什么下面的函数不会产生Clang的尾递归?
template<typename T>
constexpr bool is_prime(T number, T limit, T counter)
{
return counter >= limit
? number % limit != 0
: number % counter
? is_prime(number, number/counter, counter + 2)
: false;
}
template<typename T>
constexpr bool is_prime(T n)
{
return n == 2 || n == 3 || n == 5
? true
: n <= 1 || n % 2 == 0
? false
: is_prime(n, n/3, T{3});
}
但改变一条线(让一个布尔结果“非归一化”),它就不再产生尾递归对象代码:
template<typename T>
constexpr bool is_prime(T number, T limit, T counter)
{
return counter >= limit
? number % limit // changed here
: number % counter
? is_prime(number, number/counter, counter + 2)
: false;
}
template<typename T>
constexpr bool is_prime(T n)
{
return n == 2 || n == 3 || n == 5
? true
: n <= 1 || n % 2 == 0
? false
: is_prime(n, n/3, T{3});
}
它铛没有正确地优化它或有一个合乎逻辑的原因吗?
要强制运行评价,x
是一个运行时不可或缺的首要≥ 13
(一个递归),或足够大的constexpr主要是将防止由于大量递归深度编译时评价:
is_prime(x);
删除!= 0意味着三元语句的结果可能不是一个布尔值。结果必须转换为正确的类型,因此递归调用不是最后一个语句。 – krsteeve
@krsteeve我以前就想过这个,但对我来说这没有意义。这是一个简单的分支,如果执行不会达到'number%limit',它将被丢弃,所以,没有必要为下一次调用保存状态,它可以被丢弃,尽管它是'!= 0 '在我看来,不是。 –
经过多一点挖掘 - 如果你有exp1? exp2:exp3,确定?:语句的类型,将exp3的类型转换为exp2的类型(如果可能)。这意味着你不错的布尔结果被转换成T类型,并且必须被转换回布尔值才能返回。我很好奇,如果你反悔你的?:声明 – krsteeve