无限模板实例化

Infinite template instantiation

本文关键字:实例化 无限      更新时间:2023-10-16

这是我简化的测试代码:

struct Test {
    Test() { run(0); }
    template<class T>
    static auto run(T&&, bool stop = false) -> void { if (!stop) _run<T>(); }
    template<class R>
    static auto _run() -> void { [] () { run([] () {}, true); }(); }
};

当我使用 GCC 和 clang 编译此代码时,它给出了编译错误:

/media/data/caca3d/src/b0util/test/tst_promise.cpp:30: error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
 static auto _run() -> void { [] () { run([] () {}, true); }(); }
                                      ~~~^~~~~~~~~~~~~~~~

我不明白为什么这段代码会导致无限的模板实例化。

仅供参考,如果我删除_run()函数中的template<class R>,错误就消失了。

我在尝试使用 lambda 函数进行一些延迟计算时发现了此错误,因此我无法删除 lambda 中的间接调用。如何解决此问题?

让我们仔细看看发生了什么。第一个函数显式调用_run()的模板化版本,我想你对这部分没有疑问。

template<class T>
static auto run(T&&, bool stop = false) -> void { if (!stop) _run<T>(); }

第二个更有趣。看起来它只会实例化一次(因为你只是用 lambda 调用run()一次),但根据标准,每个 lambda 都有自己独特的类型,所以每次实例化 _run() 时,它都会强制创建一个新版本的run()(因为T是从函数的参数类型推导出来的), 创建一个无限循环。

template<class R>
static auto _run() -> void { [] () { run([] () {}, true); }(); }

在此特定示例中解决此问题的最简单方法是run()采用与您的 lambda 匹配的特定(可能与模板参数相关)类型的std::function