c++ 可变参数模板实例化深度超过最大值 900

D.p*_*.pz 5 c++ variadic-templates c++11 trailing-return-type

我正在使用 c++11 可变参数模板,但是编译器抱怨模板实例化深度超过 900 的最大值,代码如下所示:

template<typename F1, typename F2>
composed<F1, F2> compose(F1 f1, F2 f2) {
    return composed<F1, F2>(f1, f2);
}
template<typename F1, typename F2, typename... Fs>
auto compose(F1 f1, F2 f2, Fs... fs) ->decltype(compose(compose(f1, f2), fs...)) {
    return compose(compose(f1, f2), fs...);
}
Run Code Online (Sandbox Code Playgroud)

我正在使用这个模板,如:

auto composed_func = compose(f1, f2, f3, f4);
Run Code Online (Sandbox Code Playgroud)

但是,如果我将可变参数模板定义更改为:

template<typename F1, typename F2, typename F3, typename... Fs>
auto compose(F1 f1, F2 f2, F3 f3, Fs... fs) ->decltype(compose(compose(f1, f2), f3, fs...)) {
    return compose(compose(f1, f2), f3, fs...);
}
Run Code Online (Sandbox Code Playgroud)

它会正常工作。我不清楚为什么会这样。在我看来,上面的用法看起来也有效,因为它仍然递归地减少调用 compose 的 args。

Jar*_*d42 3

你可以用以下方法修复它:

template<typename F1, typename F2>
composed<F1, F2> compose(F1 f1, F2 f2) {
    return composed<F1, F2>(f1, f2);
}

template<typename F1, typename F2, typename... Fs>
auto compose(F1 f1, F2 f2, Fs... fs)
->decltype(compose(::compose(f1, f2), fs...))
{
    return compose(compose(f1, f2), fs...);
}
Run Code Online (Sandbox Code Playgroud)

演示

不合格的名称可以通过 ADL 找到,并且名称在实例化时进行搜索。

因此,通过不合格的查找,我们首先生成候选者(即使它们不是更好的匹配)

compose(f, g)可:

  • template<typename F1, typename F2> compose
  • 或者template<typename F1, typename F2, typename...Fs> compose。(带FS空包)

对于后一种情况,我们必须decltype(compose(compose(f, g)))再次解决compose(f, g)-> 无限递归。

另一方面,限定名称会立即搜索,并且只能找到完全声明的函数(因此不能找到其本身,因为尾随返回类型是声明的一部分)。因此::compose避免将自己视为重载的候选者。