编译器尝试在constexpr if之后评估无法访问的代码

Hen*_*ikS 11 c++ recursion templates template-meta-programming c++17

我最近试验过C++ 17并发现了这个:

template<size_t i>
void recurse()
{
    if constexpr(i == 0)
        return;
    return recurse<i - 1>();
}
Run Code Online (Sandbox Code Playgroud)

试着打电话recurse<4>();会导致

fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum) return recurse<i - 1>();

添加其他修复错误:

template<size_t i>
void recurse()
{
    if constexpr(i == 0)
        return;
    else
        return recurse<i - 1>();
}
Run Code Online (Sandbox Code Playgroud)

这是一个错误吗?不幸的是,我现在无法访问除gcc 7.3.0之外的其他编译器.

max*_*x66 12

不:不是错误.

这两个if constexprelse是必要的.

在你的第一个版本

template<size_t i>
void recurse()
{
    if constexpr(i == 0)
        return;
    return recurse<i - 1>();
}
Run Code Online (Sandbox Code Playgroud)

recurse<i-1>()还编译时i == 0,从而产生recurse<-1>(),从而产生recurse<-2>()

在结束递归时,您需要else链接return recurse<i-1>()if constexpr (i == 0)并避免编译i == 0.

您可以尝试删除第二个版本 constexpr

template<size_t i>
void recurse()
{
    if (i == 0)
        return;
    else
        return recurse<i - 1>();
}
Run Code Online (Sandbox Code Playgroud)

并且你应该得到相同的"模板实例化深度超过最大值900"的递归错误.

  • @HenrikS - 据我所知,编译器*可以*删除无法访问的代码; 用`if constexpr`(以及相应的`else`)*必须*删除它.那个'else`是必要的,以确保删除不必要的代码. (3认同)