Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.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++ 编译器尝试在constexpr之后计算无法访问的代码,如果_C++_Templates_Recursion_C++17_Template Meta Programming - Fatal编程技术网

C++ 编译器尝试在constexpr之后计算无法访问的代码,如果

C++ 编译器尝试在constexpr之后计算无法访问的代码,如果,c++,templates,recursion,c++17,template-meta-programming,C++,Templates,Recursion,C++17,Template Meta Programming,我最近尝试了C++17,发现: template<size_t i> void recurse() { if constexpr(i == 0) return; return recurse<i - 1>(); } 模板 void recurse() { 如果constexpr(i==0) 返回; 返回recurse(); } 尝试调用recurse()将导致 致命错误:模板实例化深度超过最大值900(使用-ftemplate dept

我最近尝试了C++17,发现:

template<size_t i>
void recurse()
{
    if constexpr(i == 0)
        return;
    return recurse<i - 1>();
}
模板
void recurse()
{
如果constexpr(i==0)
返回;
返回recurse();
}
尝试调用
recurse()将导致

致命错误:模板实例化深度超过最大值900(使用-ftemplate depth=增加最大值)
返回recurse()

添加else可修复此错误:

template<size_t i>
void recurse()
{
    if constexpr(i == 0)
        return;
    else
        return recurse<i - 1>();
}
模板
void recurse()
{
如果constexpr(i==0)
返回;
其他的
返回recurse();
}
这是虫子吗?不幸的是,我现在没有权限访问gcc 7.3.0以外的其他编译器。

否:这不是一个bug

if constexpr
else
都是必需的

在你的第一个版本中

template<size_t i>
void recurse()
{
    if constexpr(i == 0)
        return;
    return recurse<i - 1>();
}

您应该得到相同的“模板实例化深度超过最大900”递归错误。

在gcc 8.1和其他一些gcc版本上也是如此。我认为,静态if需要else分支,因为如果没有,编译器总是生成recurse()调用。

max66的答案很好,但作为多年来实现了各种解析器甚至简单编译器的人,让我为您提供更多的上下文

让我们先把这件事弄清楚:只有在标准强制执行它(或者GCC将您想要的行为记录为语言扩展)的情况下,它才是一个bug

但是,该标准不能强制删除不可访问的代码,因为检测哪些代码不可访问是一项重要任务。这一点可以通过将其减少到最小值来证明。假设
comp
是一个图灵机计算,
n
是一个非负整数值(无界类型),而
halts
是一个函数,它最多执行
n
comp
迭代,并返回是否达到停止状态。现在考虑下面的伪代码:

if ( halts(comp, n) )
    print "Halted.";
因此,确定
print
语句是否可访问需要解决
comp
的停止问题,这是一个任意图灵机计算-不可能

现在你可能会说,这是一个非常做作的推理,与像你的例子这样明显可判定的案例无关。然而,认为关于“显而易见”和语言标准的措辞的直觉假设是两个非常不同的事情。换言之,委员会将需要选择“可检测”案例的子集,并仔细指定在何种情况下需要实施以检测无法到达的代码(并及时修剪评估树)。编译器供应商将不得不花费大量时间来实现这些规则。(请记住,软件传统上是按照“硬编码”的逻辑规则运行的,不会“直觉”其所需的行为。也许有一天,我们会有人工智能编译器自动完成“正确的事情”,但我们目前甚至还没有接近这一点。)


长话短说——虽然可以采取这样的方法,但资源有限,还有许多更重要的问题需要解决。在您的示例中,需要通过添加
else
来明确分支结构的不便确实很小。

通常编译器会删除不可检查的代码。由于if constexpr if的结果在编译时已知,编译器也知道第二个return语句从未到达,因此应该能够删除它。另一方面,额外的“其他”并没有真正的伤害;)@据我所知,编译器可以删除无法访问的代码;必须使用
if constexpr
(以及相应的
else
)将其删除。必须确保删除不必要的代码。@HenrikS编译器必须确定程序的可观察行为,以确保它不会改变它。
如果constexpr
允许它在确定期间跳过块,那么size\t是“unsigned int”类型,这意味着负数被转换为巨大的数字,这就是为什么在这种情况下最大值超过900。
if ( halts(comp, n) )
    print "Halted.";