元整数平方根的无限递归
你好,
我的一个朋友正在询问如何将整数平方根函数转换为元函数。这是原始函数:
unsigned isqrt(unsigned value)
{
unsigned sq = 1, dlt = 3;
while(sq<=value)
{
sq += dlt;
dlt += 2;
}
return (dlt>>1) - 1;
}
我使用 constexpr
编写了一个元版本,但他说由于某种原因他不能使用新功能:
constexpr std::size_t isqrt_impl
(std::size_t sq, std::size_t dlt, std::size_t value){
return sq <= value ?
isqrt_impl(sq+dlt, dlt+2, value) : (dlt >> 1) - 1;
}
constexpr std::size_t isqrt(std::size_t value){
return isqrt_impl(1, 3, value);
}
所以我认为将其转换为应该不难递归地调用它自身的模板结构:
template <std::size_t value, std::size_t sq, std::size_t dlt>
struct isqrt_impl{
static const std::size_t square_root =
sq <= value ?
isqrt_impl<value, sq+dlt, dlt+2>::square_root :
(dlt >> 1) - 1;
};
template <std::size_t value>
struct isqrt{
static const std::size_t square_root =
isqrt_impl<value, 1, 3>::square_root;
};
不幸的是,这会导致无限递归(在 GCC 4.6.1 上),我无法弄清楚代码出了什么问题。错误如下:
C:\test>g++ -Wall test.cpp
test.cpp:6:119: error: template instantiation depth exceeds maximum of 1024 (use
-ftemplate-depth= to increase the maximum) instantiating 'struct isqrt_impl<25u
, 1048576u, 2049u>'
test.cpp:6:119: recursively instantiated from 'const size_t isqrt_impl<25u, 4u
, 5u>::square_root'
test.cpp:6:119: instantiated from 'const size_t isqrt_impl<25u, 1u, 3u>::squar
e_root'
test.cpp:11:69: instantiated from 'const size_t isqrt<25u>::square_root'
test.cpp:15:29: instantiated from here
test.cpp:6:119: error: incomplete type 'isqrt_impl<25u, 1048576u, 2049u>' used i
n nested name specifier
谢谢大家,
Good day,
A friend of mine is asking about transforming an integer square root function into a meta-function. Here is the original function:
unsigned isqrt(unsigned value)
{
unsigned sq = 1, dlt = 3;
while(sq<=value)
{
sq += dlt;
dlt += 2;
}
return (dlt>>1) - 1;
}
I wrote a meta version using constexpr
, but he said he can't use the new feature for some reason:
constexpr std::size_t isqrt_impl
(std::size_t sq, std::size_t dlt, std::size_t value){
return sq <= value ?
isqrt_impl(sq+dlt, dlt+2, value) : (dlt >> 1) - 1;
}
constexpr std::size_t isqrt(std::size_t value){
return isqrt_impl(1, 3, value);
}
So I thought it shouldn't be that hard to transform that into template struct that calls it self recursively:
template <std::size_t value, std::size_t sq, std::size_t dlt>
struct isqrt_impl{
static const std::size_t square_root =
sq <= value ?
isqrt_impl<value, sq+dlt, dlt+2>::square_root :
(dlt >> 1) - 1;
};
template <std::size_t value>
struct isqrt{
static const std::size_t square_root =
isqrt_impl<value, 1, 3>::square_root;
};
Unfortunately, this is causing infinite recursion(on GCC 4.6.1) and I am unable to figure out what is wrong with the code. Here is the error:
C:\test>g++ -Wall test.cpp
test.cpp:6:119: error: template instantiation depth exceeds maximum of 1024 (use
-ftemplate-depth= to increase the maximum) instantiating 'struct isqrt_impl<25u
, 1048576u, 2049u>'
test.cpp:6:119: recursively instantiated from 'const size_t isqrt_impl<25u, 4u
, 5u>::square_root'
test.cpp:6:119: instantiated from 'const size_t isqrt_impl<25u, 1u, 3u>::squar
e_root'
test.cpp:11:69: instantiated from 'const size_t isqrt<25u>::square_root'
test.cpp:15:29: instantiated from here
test.cpp:6:119: error: incomplete type 'isqrt_impl<25u, 1048576u, 2049u>' used i
n nested name specifier
Thanks all,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我没有看到
isqrt_impl
的基本案例专门化。您需要针对基本情况有一个模板专门化才能打破这种递归。这是一个简单的尝试:I don't see a base case specialization for
isqrt_impl
. You need to have a template specialization for the base case to break this recursion. Here is a simple attempt at that:默认情况下,模板评估不是惰性的。
无论条件如何,都将始终实例化模板。您需要 boost::mpl::eval_if 或等效的东西才能使该解决方案发挥作用。
或者,您可以有一个基本案例部分模板专业化,如果满足条件,则停止递归,就像 K-ballos 答案中一样。
实际上,我更喜欢使用某种形式的惰性求值而不是部分专业化的代码,因为我觉得它更容易理解,并且可以降低模板带来的噪音。
Template evaluation isn't lazy by default.
will always instantiate the template, no matter what the condition. You need
boost::mpl::eval_if
or something equivalent to get that solution to work.Alternatively you can have a base case partial template specialization that stops the recursion if the condition is met, like in K-ballos answer.
I'd actually prefer code that uses some form of lazy evaluation over partial specialization because I feel it is easier to comprehend and keeps the noise that comes with templates lower.