Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 亚整数平方根中的无限递归_C++_Templates_Recursion_Metaprogramming_Square Root - Fatal编程技术网

C++ 亚整数平方根中的无限递归

C++ 亚整数平方根中的无限递归,c++,templates,recursion,metaprogramming,square-root,C++,Templates,Recursion,Metaprogramming,Square Root,你好 我的一个朋友正在询问如何将整数平方根函数转换为元函数。以下是原始函数: unsigned isqrt(unsigned value) { unsigned sq = 1, dlt = 3; while(sq<=value) { sq += dlt; dlt += 2; } return (dlt>>1) - 1; } 所以我认为将其转换为自递归调用它的模板结构应该不难: template <

你好

我的一个朋友正在询问如何将整数平方根函数转换为元函数。以下是原始函数:

unsigned isqrt(unsigned value)
{
    unsigned sq = 1, dlt = 3;
    while(sq<=value)
    {
        sq  += dlt;
        dlt += 2;
    }
    return (dlt>>1) - 1;
}
所以我认为将其转换为自递归调用它的模板结构应该不难:

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;
};
模板
结构isqrt\u impl{
静态常量标准::大小\u t平方根=
sq>1)-1;
};
模板
结构isqrt{
静态常量标准::大小\u t平方根=
isqrt_impl::平方根;
};
不幸的是,这导致了无限递归(在GCC4.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
C:\test>g++-Wall test.cpp
test.cpp:6:119:错误:模板实例化深度超过最大值1024(使用
-ftemplate depth=增加最大值)实例化“struct isqrt_impl”
test.cpp:6:119:从“const size\u t isqrt\u impl::square\u root”递归实例化
test.cpp:6:119:从“const size\u t isqrt\u impl::squar”实例化
e_根'
test.cpp:11:69:从“const size\u t isqrt::square\u root”实例化
test.cpp:15:29:从此处实例化
test.cpp:6:119:错误:使用了不完整的类型“isqrt_impl”
n嵌套名称说明符
谢谢大家

不幸的是,这导致了无限递归(在GCC4.6.1上),我无法找出代码的错误

我没有看到
isqrt\u impl
的基本案例专门化。您需要对基本情况进行模板专门化,以打破这种递归。下面是一个简单的尝试:

template <std::size_t value, std::size_t sq, std::size_t dlt, bool less_or_equal = sq <= value >
struct isqrt_impl;

template <std::size_t value, std::size_t sq, std::size_t dlt>
struct isqrt_impl< value, sq, dlt, true >{
    static const std::size_t square_root = 
        isqrt_impl<value, sq+dlt, dlt+2>::square_root;
};

template <std::size_t value, std::size_t sq, std::size_t dlt>
struct isqrt_impl< value, sq, dlt, false >{
    static const std::size_t square_root = 
        (dlt >> 1) - 1;
};
模板{
静态常量标准::大小\u t平方根=
isqrt_impl::平方根;
};
模板
结构isqrt_impl{
静态常量标准::大小\u t平方根=
(dlt>>1)-1;
};

默认情况下,模板评估不是惰性的

static const std::size_t square_root = 
    sq <= value ?
    isqrt_impl<value, sq+dlt, dlt+2>::square_root :
    (dlt >> 1) - 1;
static const std::size\t square\u root=
sq>1)-1;
将始终实例化模板,无论条件如何。您需要
boost::mpl::eval_if
或类似的工具才能使该解决方案发挥作用

或者,您可以有一个基本情况部分模板专门化,如果满足条件,它将停止递归,如K-ballos answer


事实上,我更喜欢使用某种形式的惰性求值而不是部分专门化的代码,因为我觉得它更容易理解,并且可以降低模板带来的噪音。

如果使用递归函数,那么实际的递归深度是多少?@Sharptoth任何值都会发生这种情况,这并不是因为使用的值导致溢出。谢谢,我不知道不管三元运算符中的条件如何,模板都会被实例化。现在已经非常清楚了。@AraK我将用K-ballos解决方案补充我的答案,以得到一个公认的全面答案。非常感谢,我感谢你的回答。我真的不明白为什么我首先需要专业化。这就是我选择@pmr-answer的原因,但是你的答案非常好。我会让我的朋友看到你的答案,作为他问题的答案。@AraK:这个网站允许你重新分配所选的答案。只需单击此答案旁边的空“复选标记”。
static const std::size_t square_root = 
    sq <= value ?
    isqrt_impl<value, sq+dlt, dlt+2>::square_root :
    (dlt >> 1) - 1;